diff --git a/.changeset/tangy-sides-crash.md b/.changeset/tangy-sides-crash.md new file mode 100644 index 00000000000..318a91808ce --- /dev/null +++ b/.changeset/tangy-sides-crash.md @@ -0,0 +1,5 @@ +--- +'@clerk/nextjs': patch +--- + +Updates middleware location check to account for proxy.ts in next 16+ applications. diff --git a/packages/nextjs/src/app-router/server/auth.ts b/packages/nextjs/src/app-router/server/auth.ts index 3a4f0efd544..2a332e44162 100644 --- a/packages/nextjs/src/app-router/server/auth.ts +++ b/packages/nextjs/src/app-router/server/auth.ts @@ -11,7 +11,7 @@ import { unauthorized } from '../../server/nextErrors'; import type { AuthProtect } from '../../server/protect'; import { createProtect } from '../../server/protect'; import { decryptClerkRequestData } from '../../server/utils'; -import { isNextWithUnstableServerActions } from '../../utils/sdk-versions'; +import { isNext16OrHigher, isNextWithUnstableServerActions } from '../../utils/sdk-versions'; import { buildRequestLike } from './utils'; /** @@ -81,7 +81,8 @@ export const auth: AuthFn = (async (options?: AuthOptions) => { try { const isSrcAppDir = await import('../../server/fs/middleware-location.js').then(m => m.hasSrcAppDir()); - return [`Your Middleware exists at ./${isSrcAppDir ? 'src/' : ''}middleware.(ts|js)`]; + const fileName = isNext16OrHigher ? 'middleware.(ts|js) or proxy.(ts|js)' : 'middleware.(ts|js)'; + return [`Your Middleware exists at ./${isSrcAppDir ? 'src/' : ''}${fileName}`]; } catch { return []; } diff --git a/packages/nextjs/src/server/fs/middleware-location.ts b/packages/nextjs/src/server/fs/middleware-location.ts index 3586d4a1ae2..67a7393e20d 100644 --- a/packages/nextjs/src/server/fs/middleware-location.ts +++ b/packages/nextjs/src/server/fs/middleware-location.ts @@ -1,3 +1,4 @@ +import { isNext16OrHigher } from '../../utils/sdk-versions'; import { nodeCwdOrThrow, nodeFsOrThrow, nodePathOrThrow } from './utils'; function hasSrcAppDir() { @@ -12,12 +13,17 @@ function hasSrcAppDir() { function suggestMiddlewareLocation() { const fileExtensions = ['ts', 'js'] as const; + // Next.js 16+ supports both middleware.ts (Edge runtime) and proxy.ts (Node.js runtime) + const fileNames = isNext16OrHigher ? ['middleware', 'proxy'] : ['middleware']; + const fileNameDisplay = isNext16OrHigher ? 'middleware or proxy' : 'middleware'; + const suggestionMessage = ( + fileName: string, extension: (typeof fileExtensions)[number], to: 'src/' | '', from: 'src/app/' | 'app/' | '', ) => - `Clerk: clerkMiddleware() was not run, your middleware file might be misplaced. Move your middleware file to ./${to}middleware.${extension}. Currently located at ./${from}middleware.${extension}`; + `Clerk: clerkMiddleware() was not run, your ${fileNameDisplay} file might be misplaced. Move your ${fileNameDisplay} file to ./${to}${fileName}.${extension}. Currently located at ./${from}${fileName}.${extension}`; const { existsSync } = nodeFsOrThrow(); const path = nodePathOrThrow(); @@ -31,9 +37,11 @@ function suggestMiddlewareLocation() { to: 'src/' | '', from: 'src/app/' | 'app/' | '', ): string | undefined => { - for (const fileExtension of fileExtensions) { - if (existsSync(path.join(basePath, `middleware.${fileExtension}`))) { - return suggestionMessage(fileExtension, to, from); + for (const fileName of fileNames) { + for (const fileExtension of fileExtensions) { + if (existsSync(path.join(basePath, `${fileName}.${fileExtension}`))) { + return suggestionMessage(fileName, fileExtension, to, from); + } } } return undefined; diff --git a/packages/nextjs/src/utils/sdk-versions.ts b/packages/nextjs/src/utils/sdk-versions.ts index 729a096a6f9..e470186ca07 100644 --- a/packages/nextjs/src/utils/sdk-versions.ts +++ b/packages/nextjs/src/utils/sdk-versions.ts @@ -8,4 +8,9 @@ const isNext13 = nextPkg.version.startsWith('13.'); */ const isNextWithUnstableServerActions = isNext13 || nextPkg.version.startsWith('14.0'); -export { isNext13, isNextWithUnstableServerActions }; +/** + * Next.js 16+ renamed middleware.ts to proxy.ts + */ +const isNext16OrHigher = nextPkg.version.startsWith('16.') || parseInt(nextPkg.version.split('.')[0]) >= 16; + +export { isNext13, isNextWithUnstableServerActions, isNext16OrHigher };