DEV Community

Alex Spinov
Alex Spinov

Posted on

Remix v2 Has a Free API — Heres How to Build Full-Stack Apps With It

Remix v2 gives you a full-stack framework with built-in data loading, mutations, and server-side rendering.

Why Remix v2?

  • Nested routes: Each route is a boundary with its own data and error handling
  • Server-first: Data loads on the server, HTML streams to client
  • Progressive enhancement: Forms work without JavaScript
  • Web Fetch API: Standard Request/Response everywhere
  • Vite-powered: Lightning-fast HMR and builds

Quick Setup

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

Route-Based Data Loading

Every route exports a loader that runs on the server:

import { json } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';

export async function loader() {
  const posts = await db.post.findMany({ orderBy: { createdAt: 'desc' }, take: 20 });
  return json({ posts });
}

export default function Posts() {
  const { posts } = useLoaderData<typeof loader>();
  return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>;
}
Enter fullscreen mode Exit fullscreen mode

Mutations with Actions

import { redirect } from '@remix-run/node';
import { Form } from '@remix-run/react';

export async function action({ request }) {
  const formData = await request.formData();
  await db.post.create({ data: { title: formData.get('title'), body: formData.get('body') } });
  return redirect('/posts');
}

export default function NewPost() {
  return (
    <Form method="post">
      <input name="title" />
      <textarea name="body" />
      <button type="submit">Create</button>
    </Form>
  );
}
Enter fullscreen mode Exit fullscreen mode

Nested Routes

app/routes/
  _index.tsx          -> /
  posts.tsx           -> /posts layout
  posts._index.tsx    -> /posts index
  posts.$id.tsx       -> /posts/:id
Enter fullscreen mode Exit fullscreen mode

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 getFastData(), slow: getSlowData() });
}

export default function Page() {
  const { fast, slow } = useLoaderData<typeof loader>();
  return (
    <div>
      <h1>{fast.title}</h1>
      <Suspense fallback={<p>Loading...</p>}>
        <Await resolve={slow}>{data => <p>{data.content}</p>}</Await>
      </Suspense>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Resource Routes for APIs

export async function loader({ request }) {
  const url = new URL(request.url);
  const posts = await db.post.findMany({ where: { title: { contains: url.searchParams.get('q') } } });
  return json(posts);
}
Enter fullscreen mode Exit fullscreen mode

Real-World Use Case

A SaaS team migrated from Next.js to Remix v2. Bundle size dropped 40%, client-side waterfalls eliminated, and forms worked without JS.


Need to automate data collection for YOUR project? Check out my Apify actors for ready-made scrapers, or email spinov001@gmail.com for custom solutions.

Top comments (0)