Remix Intro
Remix (now React Router 7 framework mode) doubles down on the web platform - forms, loaders, nested routes, progressive enhancement.
Remix essentials
EXAMPLE
// 1. Scaffold
// npx create-remix@latest myapp
// app/routes/_index.tsx - route with loader + action
import { json, type LoaderFunctionArgs, type ActionFunctionArgs } from '@remix-run/node';
import { useLoaderData, Form, useNavigation } from '@remix-run/react';
export async function loader({ request }: LoaderFunctionArgs) {
const url = new URL(request.url);
const q = url.searchParams.get('q') || '';
const users = await db.users.find({ name: { $regex: q, $options: 'i' } }).toArray();
return json({ users, q });
}
export async function action({ request }: ActionFunctionArgs) {
const fd = await request.formData();
const id = String(fd.get('id'));
await db.users.deleteOne({ _id: id });
return null;
}
export default function Index() {
const { users, q } = useLoaderData<typeof loader>();
const nav = useNavigation();
return (
<div>
<Form method='get'>
<input type='search' name='q' defaultValue={q} />
<button type='submit'>Search</button>
</Form>
{nav.state === 'loading' && <p>loading...</p>}
<ul>
{users.map((u) => (
<li key={u._id}>
{u.name}
<Form method='post' style={{ display: 'inline' }}>
<input type='hidden' name='id' value={u._id} />
<button>delete</button>
</Form>
</li>
))}
</ul>
</div>
);
}
// 2. Nested routes
// app/routes/users.tsx - parent
// app/routes/users.$id.tsx - child
// Parent uses <Outlet /> to render the child.
// 3. Error boundaries per route
export function ErrorBoundary() {
return <div>Something went wrong.</div>;
}
// 4. Streaming with defer
import { defer } from '@remix-run/node';
import { Await, useLoaderData } from '@remix-run/react';
import { Suspense } from 'react';
export async function loader() {
return defer({
fast: await getStats(),
slow: getRecentActivity(), // not awaited
});
}
export default function() {
const { fast, slow } = useLoaderData<typeof loader>();
return (
<div>
<p>Active: {fast.active}</p>
<Suspense fallback={<p>loading activity...</p>}>
<Await resolve={slow}>{(list) => <List items={list} />}</Await>
</Suspense>
</div>
);
}
// 5. Deploy
// Vercel, Netlify, Cloudflare Pages, Fly, AWS Amplify - all have Remix targets.
// Choose based on edge needs vs Node features (e.g. crypto, fs).
Why it matters
Remix is the bet on the web platform - Forms, URLs, and HTTP responses as the primary API. Loaders + actions remove the data-fetching boilerplate; nested routes give you UI structure. Choose Remix when SEO and forms matter; choose Next when RSC + Vercel does.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// Remix route
export function loader() { return { msg: 'hi' }; }
export default function Index() { const { msg } = useLoaderData(); return <h1>{msg}</h1>; }
Try it Yourself »
Discussion
Loading…