Skip to content
Back to Deployment

Deploying Remix Apps

Full-stack web framework with nested routing and server-side data loading, deploy to Vercel, Fly.io, or Node.

PlatformsIntermediate

Why

Remix leverages web standards (Request/Response, forms) and nested routing to load data in parallel at the route level. Its server-first approach gives excellent SEO and progressive enhancement without client JS.

Platform-as-a-Service adoption grew 24% in 2024 as teams shift from VM management to git-push deploys. the cloud infrastructure market reached $330B in 2024, growing 22% year-over-year (Synergy Research), and PaaS layers capture the majority of new workloads.

When

Use Remix for full-stack apps needing SSR, form handling, and nested layouts. Prefer over Next.js when web-standard APIs and progressive enhancement matter.

How

1. Build — npm run build produces build/ + public/build/ 2. Vercel — @remix-run/vercel preset, git push auto-deploys 3. Fly.io — remix.init template with Dockerfile + fly.toml 4. Node — @remix-run/serve, run: remix start 5. Cloudflare — @remix-run/cloudflare, runs on Workers/Pages 6. Data loading — loader function runs on server, streams to client 7. Actions — form submissions handled server-side via action function

Example

// vite.config.ts — Vercel preset import { vitePlugin as remix } from "@remix-run/dev"; import { defineConfig } from "vite"; export default defineConfig({ plugins: [remix({ future: { v3_fetcherPersist: true } })], }); // app/routes/posts.$id.tsx — loader + action import { json } from "@remix-run/node"; import { useLoaderData, Form } from "@remix-run/react"; export async function loader({ params }) { const post = await getPost(params.id); return json({ post }); } export async function action({ request }) { const formData = await request.formData(); await updatePost(Object.fromEntries(formData)); return json({ ok: true }); } export default function Post() { const { post } = useLoaderData<typeof loader>(); return <article><h1>{post.title}</h1><Form method="post">...</Form></article>; } // Fly.io deploy — npx remix init fly && fly deploy

Common Problems

  • ⚠Loader runs on client — forgot to export from route module, runs only on server when in route
  • ⚠Form submission does full page reload — not using <Form> component from @remix-run/react
  • ⚠Session cookie too large — storing too much in session, use server-side session storage instead

Best Practices

  • ✓Use nested routing with parallel loaders — Remix loads parent + child data in one request
  • ✓Prefer <Form> over fetch for mutations — gives progressive enhancement and works without JS
  • ✓Set up health checks and graceful shutdown — handle SIGTERM to drain in-flight requests before exit

FAQ