DEV Community

Z4NR34L
Z4NR34L

Posted on • Originally published at zanreal.net

Simplify your Next.js Middleware

Motivation

I’m working with Next.js project for a few years now, after Vercel moved multiple /**/_middleware.ts files to a single /middleware.ts file, there was a unfilled gap - but just for now. After a 2023 retro I had found that there is no good solution for that problem, so I took matters into my own hands. I wanted to share that motivation with everyone here, as I think that we all need to remember how it all started.

Hope it will save you some time and would make your project DX better!

The problem

By default Next.js supports only one middleware.ts file, in which you need match routes with logic by your own which can be pretty problematic and chaotic. Also it’s endlessly making middleware boilerplate bigger.

// example code source: https://github.com/vercel/next.js/blob/canary/examples/middleware/middleware.ts

import { NextRequest, NextResponse } from 'next/server'

export function middleware(request: NextRequest) {
  if (request.nextUrl.pathname === '/about') {
    return NextResponse.redirect(new URL('/redirected', request.url))
  }
  if (request.nextUrl.pathname === '/another') {
    return NextResponse.rewrite(new URL('/rewrite', request.url))
  }
  return NextResponse.next()
}

export const config = {
  matcher: ['/about/:path*', '/another/:path*'],
}
Enter fullscreen mode Exit fullscreen mode

This exmaple is not that scary, but imagine adding more complex logic for few more routes… (ugh)

The solution

Let me introduce to you my latest package called next-easy-middleware.

Installation:

pnpm add next-easy-middleware
Enter fullscreen mode Exit fullscreen mode
npm install next-easy-middleware
Enter fullscreen mode Exit fullscreen mode
yarn add next-easy-middleware
Enter fullscreen mode Exit fullscreen mode
bun add next-easy-middleware
Enter fullscreen mode Exit fullscreen mode

Usage:

import { createMiddleware } from 'next-easy-middlewares';
import { type NextRequest, NextResponse } from 'next/server';

import { analyticsMiddleware } from '@shared/analytics/middleware';
import { authMiddleware, loginMiddleware } from '@/app/(auth)/_middleware';
import { docsMiddleware } from '@/app/(docs)/_middleware';
import { blogMiddleware, blogViewsMiddleware } from '@/app/(blog)/_middleware';
import { postsMiddleware } from '@/app/(posts)/_middleware';

const middlewares = {
  '/login': loginMiddleware,
  '/docs/:path*: docsMiddleware,
  '/blog/[slug]': blogMiddleware,
  '/blog/[slug]/view': blogViewsMiddleware,
  'regex:^/posts/\\d+$': postsMiddleware,
};

const globalMiddlewares = {
  before: authMiddleware,
  after: analyticsMiddleware
}

export const middleware = createMiddleware(middlewares, globalMiddlewares);

export const config = {
  matcher: ['/((?!api/|_next/|_static|_vercel|[\\w-]+\\.\\w+).*)'],
};
Enter fullscreen mode Exit fullscreen mode

Feedback

I’m awaiting your feedback about that solution, also feelfree to contribute to that package in below repository.

https://github.com/z4nr34l/next-easy-middlewares

Enjoy!

Top comments (0)