From 7f3bbbf99afd277c1983b21ada633cb0df0c0524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20H=C3=B6glund?= Date: Thu, 25 Jun 2026 10:41:47 +0200 Subject: [PATCH] Deprecate createRouteMatcher in nextjs --- .changeset/nextjs-deprecate-route-matcher.md | 22 ++++++++++++++++ .../src/server/__tests__/routeMatcher.test.ts | 26 +++++++++++++++++++ packages/nextjs/src/server/routeMatcher.ts | 13 ++++++++++ 3 files changed, 61 insertions(+) create mode 100644 .changeset/nextjs-deprecate-route-matcher.md create mode 100644 packages/nextjs/src/server/__tests__/routeMatcher.test.ts diff --git a/.changeset/nextjs-deprecate-route-matcher.md b/.changeset/nextjs-deprecate-route-matcher.md new file mode 100644 index 00000000000..b1979d744ef --- /dev/null +++ b/.changeset/nextjs-deprecate-route-matcher.md @@ -0,0 +1,22 @@ +--- +'@clerk/nextjs': patch +--- + +Deprecate `createRouteMatcher()` in favor of resource-based auth checks. + +Middleware-based auth checks rely on path matching, which can diverge from how Next.js routes requests and leave protected resources reachable. + +For a migration guide, see: + https://clerk.com/docs/guides/development/upgrading/upgrade-guides/migrating-from-create-route-matcher + +Instead of protecting routes from middleware, move auth checks into each protected page, layout, API route, or Server Function, for example: + +```ts +import { auth } from '@clerk/nextjs/server' + +export default async function Page() { + await auth.protect() + + return

Dashboard

+} +``` diff --git a/packages/nextjs/src/server/__tests__/routeMatcher.test.ts b/packages/nextjs/src/server/__tests__/routeMatcher.test.ts new file mode 100644 index 00000000000..d4871c93d5e --- /dev/null +++ b/packages/nextjs/src/server/__tests__/routeMatcher.test.ts @@ -0,0 +1,26 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { createRouteMatcher } from '../routeMatcher'; + +const { mockDeprecated } = vi.hoisted(() => ({ + mockDeprecated: vi.fn(), +})); + +vi.mock('@clerk/shared/deprecated', () => ({ + deprecated: mockDeprecated, +})); + +describe('createRouteMatcher', () => { + beforeEach(() => { + mockDeprecated.mockClear(); + }); + + it('should emit a deprecation warning when called', () => { + createRouteMatcher(['/foo(.*)']); + + expect(mockDeprecated).toHaveBeenCalledWith( + 'createRouteMatcher', + 'Use resource-based auth checks instead. Move auth checks into each page, layout, API route, or Server Function that accesses protected data. Middleware-based auth checks rely on path matching, which can diverge from how Next.js routes requests and leave protected resources reachable. For a migration guide, see: https://clerk.com/docs/guides/development/upgrading/upgrade-guides/migrating-from-create-route-matcher', + ); + }); +}); diff --git a/packages/nextjs/src/server/routeMatcher.ts b/packages/nextjs/src/server/routeMatcher.ts index 428fc3e9dec..b8fd30705b1 100644 --- a/packages/nextjs/src/server/routeMatcher.ts +++ b/packages/nextjs/src/server/routeMatcher.ts @@ -1,3 +1,4 @@ +import { deprecated } from '@clerk/shared/deprecated'; import { createPathMatcher, type WithPathPatternWildcard } from '@clerk/shared/pathMatcher'; import type { Autocomplete } from '@clerk/shared/types'; import type Link from 'next/link'; @@ -19,8 +20,20 @@ export type RouteMatcherParam = * You can use glob patterns to match multiple routes or a function to match against the request object. * Path patterns and regular expressions are supported, for example: `['/foo', '/bar(.*)'] or `[/^\/foo\/.*$/]` * For more information, see: https://clerk.com/docs + * + * @deprecated This function will be removed in the next major version. Use resource-based auth checks instead. + * Move auth checks into each page, layout, API route, or Server Function that accesses protected data. + * Middleware-based auth checks rely on path matching, which can diverge from how Next.js routes requests and + * leave protected resources reachable. + * + * For a migration guide, see: + * https://clerk.com/docs/guides/development/upgrading/upgrade-guides/migrating-from-create-route-matcher */ export const createRouteMatcher = (routes: RouteMatcherParam) => { + deprecated( + 'createRouteMatcher', + 'Use resource-based auth checks instead. Move auth checks into each page, layout, API route, or Server Function that accesses protected data. Middleware-based auth checks rely on path matching, which can diverge from how Next.js routes requests and leave protected resources reachable. For a migration guide, see: https://clerk.com/docs/guides/development/upgrading/upgrade-guides/migrating-from-create-route-matcher', + ); if (typeof routes === 'function') { return (req: NextRequest) => routes(req); }