Skip to content

Nr 09 Middleware

DodaTech 5 min read

title: "Next.js vs Remix — Middleware Capabilities Compared" description: "Compare middleware in Next.js and Remix including request interception, authentication, redirects, header manipulation, and route protection." weight: 19 date: 2026-06-28 lastmod: 2026-06-28 tags: [frameworks, react]

Middleware in Next.js and Remix allows you to run code before a request reaches your routes, enabling authentication, redirects, header manipulation, and logging.

What You'll Learn

You will understand middleware patterns in both frameworks, how to protect routes, handle redirects, and manipulate requests and responses.

Why It Matters

Middleware is essential for authentication, authorization, logging, A/B testing, and request preprocessing. Each framework has different middleware capabilities and limitations.

Real-World Use

DodaTech uses Next.js middleware for redirecting users based on locale and Remix middleware for authentication checks before loaders run.

flowchart LR
    A[Incoming Request] --> B[Middleware]
    B --> C{Next.js Middleware}
    B --> D{Remix Middleware}
    C --> E[Edge runtime only]
    C --> F[Rewrite/Redirect]
    C --> G[Headers/Cookies]
    D --> H[Any runtime]
    D --> I[Handle function]
    D --> J[Response headers]
    style C fill:#121212,color:#fff
    style D fill:#1a1a2e,color:#fff

Next.js Middleware

Next.js middleware runs at the edge and can intercept any request before it reaches your routes.

// middleware.js at the project root
import { NextResponse } from 'next/server';

export function middleware(request) {
  const { pathname } = request.nextUrl;
  const token = request.cookies.get('session')?.value;

  // Protect admin routes
  if (pathname.startsWith('/admin') && !token) {
    return NextResponse.redirect(new URL('/login', request.url));
  }

  // Add security headers
  const response = NextResponse.next();
  response.headers.set('X-Frame-Options', 'DENY');
  response.headers.set('X-Content-Type-Options', 'nosniff');
  return response;
}

export const config = {
  matcher: ['/admin/:path*', '/dashboard/:path*'],
};

Expected output: Middleware runs for /admin and /dashboard routes. Unauthenticated users are redirected to /login. Security headers are added to all matched responses.

Remix Loader-Level Middleware

Remix does not have a global middleware file. Implement middleware logic in individual loaders or through shared utilities.

// lib/auth.js — shared auth utility
import { redirect } from '@remix-run/node';

export async function requireUser(request) {
  const session = await getSession(request.headers.get('Cookie'));
  const userId = session.get('userId');
  if (!userId) {
    throw redirect('/login');
  }
  return userId;
}

// app/routes/admin.jsx — using the utility
import { requireUser } from '~/lib/auth';

export async function loader({ request }) {
  const userId = await requireUser(request);
  const users = await db.users.findAll();
  return { users };
}

Expected output: Each loader that needs authentication calls requireUser. If the user is not authenticated, they are redirected to /login. This is explicit per route.

Remix Handle Export for Middleware

Remix routes can export a handle object for middleware-like behavior in parent routes.

// app/routes/dashboard.jsx
import { Outlet } from '@remix-run/react';

export async function loader({ request }) {
  const userId = await requireUser(request);
  const notifications = await db.notifications.findByUserId(userId);
  return { notifications };
}

// Child routes can access parent loader data
// app/routes/dashboard.settings.jsx
export async function loader({ request }) {
  const userId = await requireUser(request); // Still need auth check
  const settings = await db.settings.findByUserId(userId);
  return { settings };
}

Expected output: Parent routes handle shared auth and data. Child routes still need their own auth checks since loaders run independently.

Comparison of Middleware Approaches

Next.js middleware runs before any route handler and can modify requests and responses globally. It runs at the edge only.

Remix handles middleware through loaders and shared utility functions. It runs in the same runtime as your routes.

Common Mistakes

  1. Putting too much logic in Next.js middleware: Middleware runs on every matched request. Keep it lightweight. Heavy computation should happen in loaders or Server Components.

  2. Forgetting that Next.js middleware only runs at the edge: Edge runtime has limited Node.js APIs. Do not use Node.js-specific modules in middleware.

  3. Not protecting every Remix loader individually: Each loader that needs authentication must check it explicitly. There is no automatic route protection.

  4. Using middleware for data fetching: Middleware is for request/response manipulation, not data fetching. Use loaders and Server Components for data.

  5. Not using the matcher config in Next.js middleware: Without a matcher, middleware runs on every request, increasing latency for all routes.

Practice Questions

  1. Where does Next.js middleware run?

At the edge, before the request reaches any route handler. It can modify the request, redirect, or rewrite URLs.

  1. How do you protect routes in Remix?

Through shared utility functions called in each loader. There is no global middleware file.

  1. What is the matcher config in Next.js middleware?

It specifies which routes the middleware should run on. Use it to avoid running middleware on every request.

  1. Can Remix modify response headers globally?

Yes, through the headers export in the root route. Individual routes can also export their own headers.

  1. What APIs are available in Next.js edge middleware?

Web standard APIs: Request, Response, URL, Headers, and crypto. Node.js-specific APIs are not available.

Challenge

Implement authentication middleware that protects an admin dashboard section. In Next.js, use middleware.js with a matcher. In Remix, create a shared requireUser utility and use it in each admin route loader.

Frequently Asked Questions

Can Next.js middleware read the request body?

No. Next.js middleware receives a Request object but the body is not available at the edge middleware layer.

Does Remix have a global middleware file?

No. Remix uses route-based middleware through loaders and shared utility functions. Each route handles its own middleware logic.

Can I use database queries in Next.js middleware?

No. Middleware runs at the edge where database drivers are not available. Use Server Components or route handlers for database access.

How do I handle CORS in Remix?

Set CORS headers in the headers export of your root route or individual routes. For complex CORS logic, use a utility function in loaders.

Can Next.js middleware set cookies?

Yes. Use request.cookies and response.cookies to read and set cookies in middleware.

Mini Project

Implement a multi-tenant application where middleware determines the tenant from the subdomain and sets a header or cookie that loaders and Server Components can read.

What's Next

Compare Authentication patterns across Next.js and Remix.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro