All Docs
FeaturesSidekickUpdated March 11, 2026

Fixing the Middleware Matcher Root Path Bug

Fixing the Middleware Matcher Root Path Bug

Release: v1.0.51

Background

Sidekick uses Auth.js (NextAuth v5) middleware in src/middleware.ts to gate access to authenticated routes. The middleware is selectively applied using a Next.js matcher pattern — routes matching the pattern are intercepted, while public routes (like the landing page, sign-in, and sign-up pages) are intended to be excluded.

The Bug

The original matcher pattern was:

export const config = {
  matcher: ['/((?!api/auth|_next/static|_next/image|favicon.ico|sign-in|sign-up|$).*)'],
};

The intent of $ at the end of the negative lookahead group was to exclude the root path / from middleware processing. However, within a lookahead group in this context, $ is treated as a literal character — it matches a dollar sign in the URL, not the end of the string. This means the root path / was not excluded and Auth.js middleware ran on every request to /.

Why It Didn't Break Anything (But Still Mattered)

Auth.js does not redirect unauthenticated users away from public pages — it simply resolves the session and passes the request through. So the landing page continued to render correctly. However:

  • Every request to / incurred the full Auth.js middleware overhead (session token validation, cookie parsing, etc.).
  • It was a subtle correctness bug that could cause unexpected behaviour if middleware logic became more strict in future.
  • It made the middleware config misleading — developers reading the pattern would expect / to be excluded.

The Fix

The matcher has been updated to explicitly list public routes that should bypass the middleware, and auth checking for public routes is delegated to the page level:

export const config = {
  matcher: ['/((?!api/auth|_next/static|_next/image|favicon.ico|sign-in|sign-up|pricing).*)'],
};

Key changes:

  • The ambiguous $ lookahead entry has been removed.
  • Public marketing/landing routes (e.g. pricing) are excluded directly in the matcher.
  • The root path / and other public routes are handled by page-level auth checks where needed, keeping the middleware focused solely on protecting authenticated surfaces.

Guidance for Custom Deployments

If you are running a self-hosted or customised version of Sidekick and have extended src/middleware.ts, audit your matcher pattern for the same issue:

  1. Do not rely on $ inside a negative lookahead within a Next.js matcher string to match end-of-string — use explicit path segments instead.
  2. List every public route you want to exclude from middleware in the lookahead group.
  3. Use page-level session checks (e.g. getServerSession() or auth()) for public pages that have conditional authenticated UI, rather than relying on the middleware to short-circuit.

Testing Your Matcher

You can verify which paths your matcher covers using a regex tester with the raw pattern (strip the surrounding /( and )):

(?!api/auth|_next/static|_next/image|favicon.ico|sign-in|sign-up|pricing).*

Test against /, /dashboard, /api/auth/session, /sign-in, and any other routes critical to your deployment.