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