AV
HomeAboutProjectBlog

© 2026 Ave syah Shina. All rights reserved.

  1. Home
  2. Blog
  3. 11 — Middleware and Route Structure — Code That Runs Before the Route

11 — Middleware and Route Structure — Code That Runs Before the Route

August 13, 20266 min read
Download as Markdown

Cross-cutting concerns like auth, localization, and bot handling need a home that runs before any route does. The model that clicked: middleware is server code that runs before a request completes, before any route renders — it can rewrite, redirect, set headers, or read cookies [1][2]. Combined with the route matcher (which decides which routes middleware runs on) and a sensible app/ structure, middleware is the place for cross-cutting concerns like auth, localization, and bot handling.

Structuring routes — the skeleton

Before middleware makes sense, the routes themselves need structure. Structuring routes means organizing the project's file system to define the app's URLs — each file under app/ (or pages/) corresponds to a route, with the file's location and name directly determining the URL path [3]. The conventions worth using:

  • Route groups — folders wrapped in parentheses, like (marketing) or (dashboard), that organize files without affecting the URL. Two route groups can each have their own root layout.
  • Private folders — folders prefixed with _ are excluded from routing, useful for colocating utilities with routes.
  • Colocation — keeping components, tests, and helpers next to the route that uses them, instead of a separate components/ sprawl.

A clear structure makes the route matcher in middleware tractable, because I'm matching against organized, named groups rather than an ad-hoc URL sprawl.

Middleware — the before-routes gate

Middleware runs on the server before a request is completed and before routes render [1][2]. Based on the incoming request, it can:

  • Rewrite the request to a different internal path without changing the URL.
  • Redirect the user to a different URL.
  • Set request or response headers.
  • Read and modify cookies.
  • Respond directly, short-circuiting the route entirely.

The classic use cases the roadmap lists: authentication, authorization, redirects based on location (localization), bot handling, and security measures [2]. Middleware is the cross-cutting concerns layer — anything that should apply to many routes without living in each one.

// middleware.ts at the project root (or src/)
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token');
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}

The flow is a decision tree at the edge, before any route renders:

request middleware matcher + cookies/headers rewrite (URL same) redirect set headers → pass respond directly route renders everything happens before the route — matcher keeps it off paths that don't need it

The route matcher — running middleware only where it matters

By default, middleware runs on every route, which is rarely what I want. The matcher config limits middleware to specific paths [4]:

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

A matcher defines patterns the request path must satisfy for the middleware to run [4]. This is the fine-grained control that keeps middleware cheap — auth checks run on protected routes only, not on every public page or static asset. Getting the matcher right is half the battle; an overly broad matcher runs middleware on requests that don't need it.

Cookies and headers — middleware's levers

Cookies and headers are the two request-time levers middleware uses most [5][6]:

  • Cookies are small pieces of data stored on the user's machine (login state, preferences, A/B test assignment). In middleware I can read and modify them before the request hits a route [5], enabling auth checks, personalization, and experimentation at the edge.
  • Headers control caching, security policies, or custom information passed to the client [6]. Setting a Content-Security-Policy or a custom x-region header across many routes is one middleware call instead of edits to each route.

How I use this

Middleware is where I put anything that must run before the route: auth checks (redirect to login if no session token), i18n locale detection (rewrite to the right locale prefix), A/B test assignment (set a cookie), and security headers. I keep the matcher tight — only the routes that actually need the check. The route structure underneath is organized into route groups so the matcher patterns read meaningfully. The discipline is: middleware for cross-cutting logic, the route itself for the page's own logic, and the matcher as the seam between them.

References

[1] Vercel, "Middleware (App Router)," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/app/api-reference/file-conventions/middleware

[2] Vercel, "Middleware — use cases," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/app/api-reference/file-conventions/middleware

[3] Vercel, "Project structure and organization," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/app/getting-started/project-structure

[4] Vercel, "Middleware — matcher," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/app/api-reference/file-conventions/middleware#matcher

[5] Vercel, "Middleware — using cookies," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/app/api-reference/file-conventions/middleware#using-cookies

[6] Vercel, "Middleware — setting headers," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/app/api-reference/file-conventions/middleware#setting-headers

[7] "Next.js 15 tutorial — Middleware," YouTube, 2024. [Video]. Available: https://www.youtube.com/watch?v=t1KTTZbqCm0

Knowledge check · Question 1 of 5

When does Next.js middleware run, relative to the route?

Comments

Leave a Comment

You must be signed in to comment

0 Comments

No comments yet. Be the first to comment!