Both Remix and Next.js are full-stack React frameworks. Next.js has the adoption lead. Remix has loyal advocates who prefer its web-standards approach. Understanding the architectural differences helps you choose.
Philosophy
Next.js: React-first. Extends React with server rendering, routing, and data fetching. Server Components, server actions, and streaming are core to the architecture.
Remix: Web-standards-first. Uses the web platform (Request/Response, FormData, HTTP caching) as the foundation. Progressive enhancement means forms work without JavaScript.
Data Loading
Next.js (App Router)
// app/posts/page.tsx (Server Component)
export default async function PostsPage() {
const posts = await db.post.findMany() // runs on server
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
Data fetching happens directly in Server Components. No special API. Just async/await.
Remix
// app/routes/posts.tsx
export async function loader() {
const posts = await db.post.findMany()
return json(posts)
}
export default function PostsPage() {
const posts = useLoaderData<typeof loader>()
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
Data loading is explicit via loader functions. Data is passed to components via useLoaderData.
Form Handling
Next.js Server Actions
// app/posts/new/page.tsx
async function createPost(formData: FormData) {
'use server'
await db.post.create({
data: {
title: formData.get('title') as string,
content: formData.get('content') as string,
},
})
redirect('/posts')
}
export default function NewPost() {
return (
<form action={createPost}>
<input name="title" />
<textarea name="content" />
<button type="submit">Create</button>
</form>
)
}
Remix Actions
// app/routes/posts.new.tsx
export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData()
await db.post.create({
data: {
title: formData.get('title') as string,
content: formData.get('content') as string,
},
})
return redirect('/posts')
}
export default function NewPost() {
return (
<Form method="post">
<input name="title" />
<textarea name="content" />
<button type="submit">Create</button>
</Form>
)
}
Both approaches use progressive enhancement (forms work without JS). Remix's action pattern is more explicit about the Request/Response cycle.
Routing
Next.js
- File-based routing in
app/directory - Folders = route segments
page.tsx,layout.tsx,loading.tsx,error.tsxconventions- Parallel routes (
@modal) - Intercepting routes (
(.)photo/[id]) - Route groups (
(marketing),(app))
Remix
- File-based routing in
app/routes/ - Flat file routing (
posts._index.tsx,posts.$id.tsx) - Nested routing with
<Outlet /> - URL-based nested layouts
- Resource routes for non-UI endpoints
Both support nested layouts and dynamic routes. Next.js has more routing features (parallel routes, intercepting routes).
Feature Comparison
| Feature | Next.js | Remix |
|---|---|---|
| Server Components | Yes (default) | No (loaders instead) |
| Streaming | Yes (Suspense) | Yes |
| Static generation | Yes (SSG, ISR) | Limited |
| Image optimization | next/image (built-in) | Manual or third-party |
| Middleware | Yes | Custom server |
| Edge rendering | Yes (edge runtime) | Yes (adapters) |
| Error boundaries | Error.tsx convention | ErrorBoundary export |
| Optimistic UI | useOptimistic hook | useFetcher |
| Prefetching | Link component | Link prefetch attribute |
| Deployment | Vercel-optimized, any Node host | Any Node host, Cloudflare, Deno |
Ecosystem and Adoption
| Metric | Next.js | Remix |
|---|---|---|
| npm weekly downloads | 7M+ | 400K+ |
| GitHub stars | 130K+ | 30K+ |
| Companies using | Vercel, Netflix, TikTok, Notion | Shopify, NASA, Sentry |
| Job postings | 15,000+ | 500+ |
| Community size | Very large | Growing |
| Backing | Vercel | Shopify |
Next.js has 15-20x the adoption of Remix.
Performance
For equivalent applications:
| Metric | Next.js | Remix |
|---|---|---|
| FCP | 0.6-1.2s | 0.6-1.0s |
| TTI | 1.0-2.0s | 0.8-1.5s |
| JS bundle (typical) | 80-150 KB | 60-100 KB |
| Waterfall requests | Minimal (Server Components) | Minimal (parallel loaders) |
Remix tends to ship slightly less JavaScript because it does not ship a Server Components runtime. The difference is small in practice.
When to Choose Next.js
- Server Components are important for your architecture
- Static generation (blogs, marketing sites, docs)
- Vercel deployment (optimized experience)
- Larger ecosystem (more libraries, tutorials, examples)
- Image optimization is critical
- Hiring (more developers know Next.js)
When to Choose Remix
- Progressive enhancement is a requirement (form submissions without JS)
- Web standards approach appeals to your team
- Cloudflare Workers deployment (better Remix adapter)
- Data-heavy applications (nested loaders parallelize data fetching)
- Smaller bundle size matters
- Shopify ecosystem (Remix is Shopify's recommended framework)
Our Choice
We use Next.js for all client projects. The Server Components architecture, ecosystem size, image optimization, and Vercel deployment give us the best foundation for shipping production applications. Remix is a well-designed framework, and we respect its web-standards approach, but Next.js's practical advantages make it our default.
Contact us to build your application with Next.js.