Next.js App Router introduced server components, cache layers, and use client boundaries. Your mental model now includes RSC payloads, parallel routes, intercepting routes, and cache revalidation strategies.
What if full-stack React just used web standards? Forms, HTTP, cookies, headers — the stuff browsers already understand?
That's Remix v2. Web platform first, framework magic second.
What Remix v2 Gives You
-
Web standards —
Request,Response,FormData,Headers— no proprietary APIs - Nested routing with parallel data loading — parent and child routes load data simultaneously
- Progressive enhancement — forms work without JavaScript, then enhance with JS
- Error boundaries per route — errors are isolated, not page-killing
-
Built-in optimistic UI —
useNavigation,useFetcherfor instant feedback - Vite-powered — fast builds, HMR, standard plugin ecosystem
Quick Start
npx create-remix@latest my-app
cd my-app && npm run dev
Loader + Action Pattern — The Core of Remix
// app/routes/contacts.$contactId.tsx
import type { LoaderFunctionArgs, ActionFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { useLoaderData, Form } from "@remix-run/react";
// GET — load data (runs on server)
export async function loader({ params }: LoaderFunctionArgs) {
const contact = await db.contact.findUnique({ where: { id: params.contactId } });
if (!contact) throw new Response("Not Found", { status: 404 });
return json({ contact });
}
// POST — handle mutations (runs on server)
export async function action({ request, params }: ActionFunctionArgs) {
const formData = await request.formData();
await db.contact.update({
where: { id: params.contactId },
data: { name: formData.get("name") as string },
});
return json({ ok: true });
}
export default function Contact() {
const { contact } = useLoaderData<typeof loader>();
return (
<Form method="post">
<input name="name" defaultValue={contact.name} />
<button type="submit">Save</button>
</Form>
);
}
This form works without JavaScript. The browser submits a POST, Remix runs the action, reloads the loader, and sends fresh HTML. With JS enabled, it intercepts the submit and does it seamlessly.
Nested Routing — Parallel Data Loading
app/routes/
_layout.tsx ← root layout (nav, sidebar)
dashboard.tsx ← /dashboard layout
dashboard._index.tsx ← /dashboard (main content)
dashboard.stats.tsx ← /dashboard/stats
dashboard.users.tsx ← /dashboard/users
When navigating to /dashboard/stats:
-
_layoutloader,dashboardloader, anddashboard.statsloader run in parallel - Only the changed route segment re-renders
- Parent layout stays mounted — no layout shift
Optimistic UI with useFetcher
function TodoItem({ todo }) {
const fetcher = useFetcher();
// Show optimistic state immediately
const isComplete = fetcher.formData
? fetcher.formData.get("complete") === "true"
: todo.complete;
return (
<fetcher.Form method="post" action={`/todos/${todo.id}`}>
<input type="hidden" name="complete" value={(!isComplete).toString()} />
<button>
{isComplete ? "✓" : "○"} {todo.title}
</button>
</fetcher.Form>
);
}
The checkbox toggles instantly — no loading spinner. If the server request fails, it reverts automatically.
Error Boundaries Per Route
// app/routes/dashboard.stats.tsx
export function ErrorBoundary() {
const error = useRouteError();
return <div>Stats failed to load. The rest of the dashboard still works.</div>;
}
If the stats route throws, only the stats panel shows an error. The dashboard layout, navigation, and other panels keep working.
When to Choose Remix v2
Choose Remix when:
- You want React without fighting the web platform
- Forms and mutations are a big part of your app
- Progressive enhancement matters (gov sites, accessibility)
- You want simpler mental model than Next.js App Router
Skip Remix when:
- You need static site generation for 10K+ pages
- Your team is already productive with Next.js
- You need React Server Components
The Bottom Line
Remix doesn't add abstractions on top of the web — it removes them. The result is code that's simpler to write, debug, and maintain.
Start here: remix.run/docs
Need custom data extraction, scraping, or automation? I build tools that collect and process data at scale — 78 actors on Apify Store and 265+ open-source repos. Email me: Spinov001@gmail.com | My Apify Actors
Top comments (0)