arrow_back Back to Blog
Engineering 10 Min Read March 2026

Remix vs Next.js in 2026:
A Practitioner's Guide

I've shipped production apps in both. Here's the unfiltered breakdown — based on real pain, not benchmarks.

Henning Botha

Henning Botha

Founder & Lead Architect

Dark screen showing React and JavaScript code

When I started building Net Terms Tracker — a full-stack Shopify B2B app — I had to make a choice that would define the project's architecture for months: Remix or Next.js? I'd used both before, but this was the first time I was forced to pick one under real production constraints: Shopify's opinionated OAuth flow, a requirement for real-time server-side data mutations, and a tight integration with Shopify's Polaris design system.

I chose Remix. This post explains why — and also when I would choose Next.js instead.

The Core Mental Model Difference

Both frameworks are React-based, but they have fundamentally different philosophies about where data lives and how it moves.

Next.js is a platform for rendering React — it gives you flexibility to mix Server Components, Client Components, API Routes, and static generation however you see fit. The power is immense. The tradeoff is that you're constantly making architectural decisions: where does this data fetch? Is this a Server Component or a Client Component? Do I need an API route for this or can I use a Server Action?

Remix is built around the web platform itself — specifically around Request / Response and the nested routing model. Every route is a full data-fetching unit with a loader (server-side GET) and an action (server-side POST/PUT/DELETE). Your UI is always a function of server state. There's far less architectural ambiguity, which I've found invaluable on complex apps.

Why Remix Won for the Shopify App

Shopify's app development model maps almost perfectly to Remix's architecture. Here's why:

1. The OAuth flow is a form submission, not a client-side dance

Shopify's OAuth install flow is a series of redirects and token exchanges. In Remix, this is just a loader on the install route that reads the query params, exchanges the code for a token, and redirects. Clean, server-rendered, no hydration weirdness.

// app/routes/auth.$.tsx — Shopify OAuth handled in a loader export async function loader({ request, context }: LoaderFunctionArgs) { const { admin, session } = await authenticate.admin(request); // If we reach here, auth succeeded. Redirect to app. return redirect("/app"); }

2. Mutations are first-class citizens

The Net Terms Tracker is mutation-heavy: approving credit applications, updating credit limits, marking invoices paid. In Next.js, each of these would typically be a Server Action or an API route that the client calls. In Remix, each of these is just an action on the relevant route. The useFetcher hook handles the loading state automatically. Less code, less complexity.

// Approving a credit application — entire mutation in one place export async function action({ request }: ActionFunctionArgs) { const formData = await request.formData(); const applicationId = formData.get("applicationId") as string; await db.creditApplication.update({ where: { id: applicationId }, data: { status: "APPROVED", reviewedAt: new Date() }, }); return json({ success: true }); }

3. Nested layouts with isolated data fetching

The admin dashboard has a persistent sidebar (merchant config, credit stats) that shouldn't re-fetch every time you navigate between sections. Remix's nested routing model handles this perfectly — the sidebar data lives in a parent route's loader, and child routes fetch only their own data independently. In Next.js with the App Router, this is achievable but requires more deliberate component boundary management.

When I'd Choose Next.js Instead

Remix is not a universal win. Here's where I'd reach for Next.js:

The Real Decision Framework

Choose Remix when: your app is mutation-heavy, your data is mostly dynamic (no static pages), you're building on a platform with server-driven flows (Shopify, OAuth-heavy apps), or you want a simpler data layer with less architectural decision-making.

Choose Next.js when: you need static generation, you're deep in the RSC ecosystem, you're on Vercel, you need a larger talent pool, or your app has a significant content/marketing surface area alongside the app itself.

Neither framework is universally better. The mistake I see founders make is treating this as a theological debate rather than a tool selection. Pick the one that maps to your problem. For B2B SaaS apps built on third-party platforms, Remix's server-first, mutation-centric model gives you a cleaner architecture with less ceremony. For content-heavy products that need fine-grained rendering control, Next.js's flexibility is unmatched.

The Bottom Line

After shipping Net Terms Tracker in Remix, I'd make the same call again. The loader/action model kept the codebase clean and the Shopify integration straightforward. But I'm also shipping a SaaS dashboard right now in Next.js 15 because the project has a heavy marketing site component and the team I'm working with knows Next.js.

Use the tool that fits the job. That's what a Forge does.

Building a Shopify app or SaaS product?

HJB CodeForge specializes in exactly this kind of work. Let's talk about your project.

Book a Free Call arrow_forward
Next Post Building Net Terms Tracker →