export async function loader() { return json({ shipped: 28, }) }
Stack Innovations
Start a project
Most React stacks treat the network as an afterthought — useEffect,
a spinner, fingers crossed. Remix puts the request first: nested routes
load loader data in parallel on the server,
<Form> + action handles every mutation, and
adapters let the same code ship to Vercel, Cloudflare, Node, Deno, Bun.
Each stat is a typed Remix loader. Hover any to see the function signature. Counters scrub with scroll — same primitives we use in production.
export async function loader() { return json({ shipped: 28, }) }
export async function loader() { return json({ routes: 5400, }) }
export async function loader() { return json({ adapters: 9, }) }
export async function loader() { return json({ spinners: 0, }) }
Click an entry on the left — the active capability opens in the Remix DevTools-feeling editor. Each pane is a working pattern we've shipped.
Flat-file routing with dot-segmented filenames: posts.$slug.tsx nests inside posts.tsx nests inside _layout.tsx. Each level keeps its own loader, header chrome, error boundary. Navigating between siblings only re-runs the loaders that actually changed.
_layout.tsx · pathless wrappers$param.tsx · dynamic segments($optional).tsx · i18n-ready<Outlet /> with shared chromehandle exports for breadcrumbsEach route exports a loader. On navigation Remix runs all matched loaders in parallel server-side, returns JSON for the client, hydrates without a single useEffect. defer() streams slow data via <Await /> so the shell paints first. Cache headers from headers().
useLoaderData<typeof loader>()defer({ slow: promise })<Await resolve={slow}>headers() · CDN taggingshouldRevalidate · skip on hopMutations are POSTs. action() receives a real Request, parses formData(), validates with Zod, writes, returns redirect() or JSON. After an action all loaders on the page automatically revalidate — UI is fresh without state-management gymnastics.
request.formData()redirect() · PRG by defaultuseActionData() · field errors<Form> is just an HTML form — with JS off, the browser submits it the normal way. useFetcher lets you submit without navigating (likes, follows, inline saves). useNavigation() exposes the in-flight intent so pending UI is one hook, not a state machine.
<Form method="post">fetcher.submit(formData)navigation.state · idle / loading / submittingfetcher.formData · optimistic inputEach route can export an ErrorBoundary. A loader throws — only that segment's UI swaps to the error view; the parent layout, nav, and surrounding content stay rendered. Both runtime errors and explicit Response throws (404, 401, 500) route here. Source maps in dev show the actual server stack.
throw new Response("Not found", { status: 404 })useRouteError() · typedisRouteErrorResponse() guardentry.serverSessions ride a signed, HTTP-only cookie — no client tokens floating around localStorage. createCookieSessionStorage handles the round-trip; flash messages survive one redirect; OAuth + Remix-Auth slot in cleanly. Per-runtime backends: KV on Cloudflare, durable on Node, in-memory in tests.
createCookieSessionStorage()session.flash() for one-shot UIThis is what makes Remix itself: nested routes load in parallel, not waterfalled like client-fetch React. Click each route's loader pill — toggle await, defer, or none. The waterfall on the right rebuilds, TTFB and total payload recompute, and the rendered page on the far right swaps in skeletons or streamed chunks accordingly.
Same framework, two very different ways it ends up shipping. Eight criteria your team will actually feel — in plain English, with the receipts.
Default config plus a SPA-shaped client bundle. Mobile feels every kilobyte and every spinner.
Lighthouse 100s as a starting line. CI fails the build on any regression.
Each component fetches on mount. Nested routes stack spinner on spinner before the page is usable.
All loaders fire in parallel on the server, page paints with data. Slow bits stream in via defer().
Custom hooks, Redux thunks, optimistic-then-rollback ladders. Errors and revalidation logic re-invented per page.
Mutations are forms. Action runs server-side, all loaders revalidate, UI is fresh. Optional optimistic via useFetcher.
Bolted on as a follow-up engagement. The "we'll get to it" version of SEO.
Sitemaps, structured data, per-route meta(), Open Graph images — live on day one.
Switching providers later means rewriting deploy pipelines and parts of the app.
Same code ships to any of them. Switching adapters is a one-file change in entry.server.
You move the routes yourself. Links break, search rankings drop, customers hit 404s.
Route inventory, redirect map, content port, dry-run, cutover. SEO continuity holds.
"Good luck with the admin." Editors learn by trial and error in production.
Editors leave training feeling fluent. First publish goes through without a Slack ping.
Hand-off, then silence. Six months later you're two majors behind on Remix.
Monthly version bumps, perf monitoring, real Slack channel. Features, not tickets.
Remix's adapter layer compiles your app to runtime-native output. Same routes, same loaders, same actions. Click any adapter — entry.server.tsx swaps to that runtime, regions and cold-start metrics update, and the build command changes. No code changes anywhere in app/.
Adapters are a thin layer that translates the runtime's request shape into a web-standard Request object Remix can read. Everything in app/ — loaders, actions, routes — stays untouched. The only difference between deployments is one file in server/.
Inventory every URL. Map each to a Remix route file. Lighthouse + TTFB baseline. Pick the adapter for the runtime.
Remix + Vite + TypeScript, design tokens, app/root.tsx, layouts, session storage, error boundaries, meta() baseline.
Routes, layouts, typed loaders, actions with Zod-validated FormData, useFetcher patterns, optimistic UI.
Image pipeline, prefetch tuning, JSON-LD, sitemap, OG images. headers() tagging, adapter wired, regions pinned.
Content + redirect map, dry-run on staging, remix vite:build against the target adapter, deploy, DNS cutover.
Remix + adapter upgrades, route-level perf monitoring, error-boundary triage, monthly review.