DEV Community

Alex Spinov
Alex Spinov

Posted on

Remix Has a Free API You've Never Heard Of

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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}` });
}
Enter fullscreen mode Exit fullscreen mode

Quick Start

npx create-remix@latest
cd my-app && npm run dev
Enter fullscreen mode Exit fullscreen mode

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)