DEV Community

Alex Spinov
Alex Spinov

Posted on

Remix v2 Has a Free Framework That Makes React Server-Side Rendering Actually Enjoyable

Remix v2 ditches the file-based routing complexity of Next.js and gives you nested routes with built-in data loading. Every route is a server component by default. No client-side waterfalls. No loading spinners everywhere.

What Changed in v2

Feature Remix v1 Remix v2
Routing file convention v1 flat routes (v2 convention)
Dev server Custom Vite
CSS Custom imports Vite CSS
Meta Object Function
Error boundary CatchBoundary + ErrorBoundary Single ErrorBoundary

Quick Start

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

Nested Routes with Data Loading

// app/routes/posts.$postId.tsx
import type { LoaderFunctionArgs } from "@remix-run/node"
import { json } from "@remix-run/node"
import { useLoaderData } from "@remix-run/react"

export async function loader({ params }: LoaderFunctionArgs) {
  const post = await db.post.findUnique({ where: { id: params.postId } })
  if (!post) throw new Response("Not Found", { status: 404 })
  return json({ post })
}

export default function Post() {
  const { post } = useLoaderData<typeof loader>()
  return <article><h1>{post.title}</h1><p>{post.content}</p></article>
}
Enter fullscreen mode Exit fullscreen mode

Actions (Server-Side Form Handling)

import { ActionFunctionArgs, redirect } from "@remix-run/node"

export async function action({ request }: ActionFunctionArgs) {
  const formData = await request.formData()
  const title = formData.get("title") as string
  await db.post.create({ data: { title } })
  return redirect("/posts")
}

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

No useState. No onSubmit handler. No fetch calls. The form just works — with progressive enhancement.

Error Boundaries

export function ErrorBoundary() {
  const error = useRouteError()
  if (isRouteErrorResponse(error)) {
    return <div>{error.status}: {error.data}</div>
  }
  return <div>Something went wrong</div>
}
Enter fullscreen mode Exit fullscreen mode

One boundary handles both expected (404) and unexpected errors per route.

Why Remix Over Next.js

  • Nested routes = parallel data loading (no waterfall)
  • Forms work without JavaScript
  • Standard Web APIs (Request, Response, FormData)
  • Simpler mental model than RSC

The Bottom Line

Remix v2 on Vite is fast, simple, and web-standards-first. If you want React SSR without the Next.js complexity, this is it.


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

Top comments (0)