Bird
Raised Fist0
NextJSframework~10 mins

Middleware.ts file convention in NextJS - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - Middleware.ts file convention
Request Received
Middleware.ts Runs
Check URL/Headers
Allow Request
Continue to Route Handler
Modify Request/Response
Redirect or Block
Response Sent
Middleware.ts runs on every request, checks or modifies it, then decides to continue, redirect, or block.
Execution Sample
NextJS
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  if (request.nextUrl.pathname.startsWith('/admin')) {
    return NextResponse.redirect(new URL('/login', request.url));
  }
  return NextResponse.next();
}
This middleware redirects users trying to access '/admin' to '/login', otherwise lets requests continue.
Execution Table
StepRequest URLConditionActionResult
1/admin/dashboardURL starts with '/admin'Redirect to '/login'Redirect response sent
2/aboutURL does not start with '/admin'ContinueRequest continues to route handler
3/admin/settingsURL starts with '/admin'Redirect to '/login'Redirect response sent
4/homeURL does not start with '/admin'ContinueRequest continues to route handler
💡 Middleware ends by either redirecting or allowing request to continue.
Variable Tracker
VariableAfter 1After 2After 3After 4
request.nextUrl.pathname/admin/dashboard/about/admin/settings/home
Action takenRedirectContinueRedirectContinue
Key Moments - 2 Insights
Why does the middleware redirect only some URLs?
Because it checks if the URL path starts with '/admin' (see execution_table rows 1 and 3). Only those matching URLs trigger the redirect.
What happens if middleware returns NextResponse.next()?
It means the middleware lets the request continue to the next handler or page (see execution_table rows 2 and 4). No redirect or block occurs.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what action is taken at step 2 when the URL is '/about'?
ARedirect to '/login'
BAllow request to continue
CBlock the request
DModify the request URL
💡 Hint
Check the 'Action' column in execution_table row 2.
At which step does the middleware send a redirect response?
ASteps 1 and 3
BStep 4
CStep 2
DAll steps
💡 Hint
Look at the 'Result' column for redirect responses in execution_table.
If the condition changed to check for '/user' instead of '/admin', what would happen at step 1?
ARedirect to '/login'
BBlock the request
CAllow request to continue
DError occurs
💡 Hint
Refer to variable_tracker for request URL and condition logic.
Concept Snapshot
Middleware.ts runs on every request in Next.js.
It checks request details like URL or headers.
Based on conditions, it can redirect, modify, or allow requests.
Use NextResponse to control flow.
Place middleware.ts in the root of the project.
It runs before route handlers or pages.
Full Transcript
Middleware.ts in Next.js is a special file that runs on every incoming request. It checks the request URL or headers and decides what to do next. For example, it can redirect users trying to access protected routes like '/admin' to a login page. If the URL does not match the condition, the middleware lets the request continue to the intended page or API. This behavior is controlled by returning NextResponse.redirect or NextResponse.next. The middleware file should be placed in the root of the project. This setup helps control access and modify requests globally before they reach your pages or API routes.

Practice

(1/5)
1. What is the primary purpose of the middleware.ts file in a Next.js project?
easy
A. To run code before requests reach pages or API routes
B. To define React components for UI rendering
C. To store global CSS styles
D. To configure database connections

Solution

  1. Step 1: Understand middleware role

    Middleware runs before the request reaches pages or APIs, allowing pre-processing.
  2. Step 2: Compare with other file roles

    React components handle UI, CSS files style, and database configs are separate; middleware is for request handling.
  3. Final Answer:

    To run code before requests reach pages or API routes -> Option A
  4. Quick Check:

    Middleware = pre-request code [OK]
Hint: Middleware runs before pages or APIs handle requests [OK]
Common Mistakes:
  • Confusing middleware with UI components
  • Thinking middleware manages styles or database
  • Assuming middleware runs after page rendering
2. Which of the following is the correct way to export a middleware function in middleware.ts?
easy
A. export default function middleware(req) { return NextResponse.next(); }
B. export function middleware(req) { NextResponse.next(); }
C. export const middleware = (req) => NextResponse.next();
D. module.exports = function middleware(req) { return NextResponse.next(); }

Solution

  1. Step 1: Identify modern export syntax

    Next.js middleware uses named export with const arrow function for clarity and modern style.
  2. Step 2: Check syntax validity

    export const middleware = (req) => NextResponse.next(); uses export const middleware = (req) => NextResponse.next(); which is valid and recommended.
  3. Final Answer:

    export const middleware = (req) => NextResponse.next(); -> Option C
  4. Quick Check:

    Use named const export for middleware [OK]
Hint: Use named const arrow function export for middleware [OK]
Common Mistakes:
  • Using CommonJS module.exports instead of ES module export
  • Using default export instead of named export
  • Declaring middleware as a regular function without export
3. Given this middleware.ts snippet, what will happen when a request to /dashboard is made?
import { NextResponse } from 'next/server';

export const config = { matcher: ['/dashboard'] };

export const middleware = (req) => {
  if (!req.cookies.get('token')) {
    return NextResponse.redirect(new URL('/login', req.url));
  }
  return NextResponse.next();
};
medium
A. The user is redirected to /login if no token cookie is present
B. The request proceeds to /dashboard regardless of cookies
C. The middleware throws a runtime error due to missing cookie method
D. The middleware blocks all requests to /dashboard

Solution

  1. Step 1: Analyze matcher and cookie check

    The middleware runs only on /dashboard and checks if 'token' cookie exists.
  2. Step 2: Determine behavior based on cookie presence

    If no token cookie, it redirects to /login; otherwise, it allows the request.
  3. Final Answer:

    The user is redirected to /login if no token cookie is present -> Option A
  4. Quick Check:

    Missing token cookie triggers redirect [OK]
Hint: Check cookie presence to decide redirect or continue [OK]
Common Mistakes:
  • Assuming middleware runs on all routes
  • Thinking request proceeds without token cookie
  • Confusing redirect URL construction
4. Identify the error in this middleware.ts code snippet:
import { NextResponse } from 'next/server';

export const middleware = (req) => {
  if (req.cookies.token === undefined) {
    return NextResponse.redirect('/login');
  }
  return NextResponse.next();
};
medium
A. Missing import of NextRequest from 'next/server'
B. Accessing cookies directly as an object instead of using req.cookies.get()
C. Using arrow function instead of regular function
D. Not exporting config.matcher for route matching

Solution

  1. Step 1: Check cookie access method

    In Next.js middleware, cookies are accessed via req.cookies.get('name'), not as object properties.
  2. Step 2: Identify error cause

    Using req.cookies.token will be undefined or cause error; correct is req.cookies.get('token').
  3. Final Answer:

    Accessing cookies directly as an object instead of using req.cookies.get() -> Option B
  4. Quick Check:

    Use req.cookies.get('token') to access cookies [OK]
Hint: Use req.cookies.get('name') to read cookies in middleware [OK]
Common Mistakes:
  • Accessing cookies as properties instead of using get() method
  • Forgetting to import NextResponse
  • Assuming arrow functions are invalid in middleware
5. You want your middleware.ts to run only on API routes starting with /api/private and redirect users without a valid auth cookie to /api/auth/unauthorized. Which config and middleware code correctly implements this?
hard
A. export const config = { matcher: ['/api/private/:path*'] }; export const middleware = (req) => { if (!req.cookies.get('auth')) { return NextResponse.rewrite(new URL('/api/auth/unauthorized', req.url)); } return NextResponse.next(); };
B. export const config = { matcher: ['/api/private/*'] }; export const middleware = (req) => { if (req.cookies.auth === undefined) { return NextResponse.redirect('/api/auth/unauthorized'); } return NextResponse.next(); };
C. export const config = { matcher: ['/api/private'] }; export default function middleware(req) { if (!req.cookies.get('auth')) { return NextResponse.redirect('/api/auth/unauthorized'); } return NextResponse.next(); };
D. export const config = { matcher: ['/api/private/:path*'] }; export const middleware = (req) => { if (!req.cookies.get('auth')) { return NextResponse.redirect(new URL('/api/auth/unauthorized', req.url)); } return NextResponse.next(); };

Solution

  1. Step 1: Verify matcher pattern for API routes

    The pattern /api/private/:path* correctly matches all routes under /api/private.
  2. Step 2: Check cookie access and redirect method

    Using req.cookies.get('auth') is correct. Redirect uses NextResponse.redirect(new URL(...)) with full URL.
  3. Step 3: Compare options for correctness

    export const config = { matcher: ['/api/private/:path*'] }; export const middleware = (req) => { if (!req.cookies.get('auth')) { return NextResponse.redirect(new URL('/api/auth/unauthorized', req.url)); } return NextResponse.next(); }; uses correct matcher, cookie access, and redirect syntax. Others have errors like wrong cookie access, missing URL object, or rewrite instead of redirect.
  4. Final Answer:

    export const config = { matcher: ['/api/private/:path*'] }; export const middleware = (req) => { if (!req.cookies.get('auth')) { return NextResponse.redirect(new URL('/api/auth/unauthorized', req.url)); } return NextResponse.next(); }; -> Option D
  5. Quick Check:

    Use matcher with :path*, get() for cookies, and redirect with URL [OK]
Hint: Use :path* matcher and req.cookies.get() with NextResponse.redirect(URL) [OK]
Common Mistakes:
  • Using wildcard * instead of :path* in matcher
  • Accessing cookies as properties instead of get()
  • Using rewrite instead of redirect for unauthorized access
  • Not wrapping redirect URL in new URL()