Remix is a full-stack React framework focused on web standards. Now merged with React Router v7, it provides server-side rendering, data loading, and mutations using the platform's native APIs — no client-side state management needed.
What Makes Remix Special?
- Web standards — uses native Request/Response, FormData, Headers
- Nested routes — parallel data loading, no waterfalls
- Progressive enhancement — forms work without JavaScript
- No client state — server is the source of truth
- React Router v7 — Remix IS React Router now
The Hidden API: Loader/Action Pattern
// app/routes/products.$id.tsx
import type { LoaderFunctionArgs, ActionFunctionArgs } from '@remix-run/node';
import { useLoaderData, Form } from '@remix-run/react';
// Server-side data loading
export async function loader({ params }: LoaderFunctionArgs) {
const product = await db.product.findUnique({ where: { id: params.id } });
if (!product) throw new Response('Not Found', { status: 404 });
return { product };
}
// Server-side mutations
export async function action({ request, params }: ActionFunctionArgs) {
const formData = await request.formData();
const intent = formData.get('intent');
switch (intent) {
case 'update':
await db.product.update({
where: { id: params.id },
data: {
title: formData.get('title') as string,
price: Number(formData.get('price'))
}
});
return { success: true };
case 'delete':
await db.product.delete({ where: { id: params.id } });
return redirect('/products');
}
}
// Component — works WITHOUT JavaScript!
export default function ProductPage() {
const { product } = useLoaderData<typeof loader>();
return (
<Form method="post">
<input name="title" defaultValue={product.title} />
<input name="price" type="number" defaultValue={product.price} />
<button name="intent" value="update">Save</button>
<button name="intent" value="delete">Delete</button>
</Form>
);
}
Resource Routes API — Build Any API
// app/routes/api.products.ts — Pure API endpoint
export async function loader({ request }: LoaderFunctionArgs) {
const url = new URL(request.url);
const search = url.searchParams.get('q') || '';
const products = await db.product.findMany({
where: { title: { contains: search } },
take: 20
});
return Response.json(products);
}
// app/routes/api.upload.ts — File upload
export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData();
const file = formData.get('file') as File;
const buffer = await file.arrayBuffer();
await saveFile(file.name, Buffer.from(buffer));
return Response.json({ url: `/uploads/${file.name}` });
}
Quick Start
npx create-remix@latest
cd my-app && npm run dev
Why Teams Choose Remix
A developer shared: "We had 50KB of Redux + React Query code managing server state. Remix replaced ALL of it with loaders and actions. Our bundle shrank 40% and the app works even with JavaScript disabled."
Building full-stack React apps? Email spinov001@gmail.com or check my tools.
Remix vs Next.js — which full-stack React framework do you prefer?
Top comments (0)