{"record":{"id":"0738c42f46be5138","repo":"withastro/astro","slug":"usage-of-vercel-edge-middleware-js-is-deprecated","errorCode":null,"errorMessage":"Usage of `vercel-edge-middleware.js` is deprecated. You can now use the `waitUntil(promise)` function directly as `ctx.locals.waitUntil(promise)`.","messagePattern":"Usage of `vercel-edge-middleware\\.js` is deprecated\\. You can now use the `waitUntil\\(promise\\)` function directly as `ctx\\.locals\\.waitUntil\\(promise\\)`\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/integrations/vercel/src/serverless/middleware.ts","lineNumber":120,"sourceCode":"\t}\n\treturn pathToFileURL(bundledFilePath);\n}\n\nfunction edgeMiddlewareTemplate(\n\tastroMiddlewareEntryPointPath: URL,\n\tvercelEdgeMiddlewareHandlerPath: URL,\n\tmiddlewareSecret: string,\n\tlogger: AstroIntegrationLogger,\n\tisrForwarding?: IsrForwarding,\n) {\n\tconst middlewarePath = JSON.stringify(\n\t\tfileURLToPath(astroMiddlewareEntryPointPath).replace(/\\\\/g, '/'),\n\t);\n\tconst filePathEdgeMiddleware = fileURLToPath(vercelEdgeMiddlewareHandlerPath);\n\tlet handlerTemplateImport = '';\n\tlet handlerTemplateCall = '{}';\n\tif (existsSync(filePathEdgeMiddleware + '.js') || existsSync(filePathEdgeMiddleware + '.ts')) {\n\t\tlogger.warn(\n\t\t\t'Usage of `vercel-edge-middleware.js` is deprecated. You can now use the `waitUntil(promise)` function directly as `ctx.locals.waitUntil(promise)`.',\n\t\t);\n\t\tconst stringified = JSON.stringify(filePathEdgeMiddleware.replace(/\\\\/g, '/'));\n\t\thandlerTemplateImport = `import handler from ${stringified}`;\n\t\thandlerTemplateCall = `await handler({ request, context })`;\n\t} else {\n\t}\n\treturn `\n\t${handlerTemplateImport}\nimport { onRequest } from ${middlewarePath};\nimport { createContext, trySerializeLocals } from 'astro/middleware';\n\nconst isrRoutes = ${JSON.stringify(isrForwarding?.isrRoutes ?? [])}.map((source) => new RegExp(source));\nconst isrExcludedRoutes = ${JSON.stringify(isrForwarding?.isrExcludedRoutes ?? [])}.map(\n\t(source) => new RegExp(source),\n);\n\nconst isCached = (pathname) =>","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/withastro/astro/blob/3578d45d34226d63cff3d261c971c221de6794d2/packages/integrations/vercel/src/serverless/middleware.ts#L102-L138","documentation":"When @astrojs/vercel generates its edge middleware bundle, generateEdgeMiddleware checks for a `vercel-edge-middleware.js` (or `.ts`) file in your `srcDir` (packages/integrations/vercel/src/index.ts:62 defines the name; the check is at serverless/middleware.ts:106). If the file exists, the adapter warns that this hook is deprecated and still wires it into the generated middleware (`import handler ...` / `await handler({ request, context })`). The replacement is calling `ctx.locals.waitUntil(promise)` (surfaced as `waitUntil` inside Astro middleware) instead of a separate edge-middleware entry file.","triggerScenarios":"Building any Astro project with the Vercel adapter in serverless mode (middleware enabled) while `src/vercel-edge-middleware.js` or `src/vercel-edge-middleware.ts` exists in the source directory. The warning is emitted from edgeMiddlewareTemplate during `astro build`; the legacy file continues to work and is imported into the generated `middleware.mjs`.","commonSituations":"Projects created from older Vercel/Astro templates or docs that instructed adding `src/vercel-edge-middleware.js` to defer work with `waitUntil`; upgrading @astrojs/vercel past the release that added native `waitUntil` support without migrating the legacy file; copying a middleware setup from an outdated blog post or example repo.","solutions":["Delete `src/vercel-edge-middleware.js` (or `.ts`) and move its logic into your Astro middleware (`src/middleware.ts`), replacing `context.waitUntil(...)` calls with `ctx.locals.waitUntil(...)` inside `onRequest`.","Verify no other code imports `vercel-edge-middleware` before deleting (search the repo for the filename).","Rebuild and confirm the warning is gone and deferred work (e.g. analytics flushing, cache revalidation) still completes by checking function logs on Vercel."],"exampleFix":"// before: src/vercel-edge-middleware.js\nexport default async function ({ request, context }) {\n  context.waitUntil(fetch('https://example.com/collect', { method: 'POST', body: request.url }));\n}\n\n// after: src/middleware.ts\nimport { defineMiddleware } from 'astro:middleware';\n\nexport const onRequest = defineMiddleware((ctx, next) => {\n  ctx.locals.waitUntil(\n    fetch('https://example.com/collect', { method: 'POST', body: ctx.url.toString() })\n  );\n  return next();\n});","handlingStrategy":"validation","validationCode":"// abort before build if the deprecated edge middleware file still exists\nimport fs from 'node:fs';\nimport path from 'node:path';\nconst legacy = ['vercel-edge-middleware.js', 'vercel-edge-middleware.ts'].map((f) =>\n  path.join('src', f)\n);\nconst found = legacy.filter((f) => fs.existsSync(f));\nif (found.length) {\n  throw new Error(`Deprecated ${found.join(', ')} found — migrate to ctx.locals.waitUntil in src/middleware.ts`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When adding deferred work in Vercel middleware, always use `ctx.locals.waitUntil(promise)` inside `src/middleware.ts` — never add a `src/vercel-edge-middleware.js` file.","Search the project for `vercel-edge-middleware` after every @astrojs/vercel major upgrade; deprecation warnings in this adapter precede removal.","Codify the existence check in a repo lint script or CI step so a legacy file re-added from an old template fails the build."],"tags":["vercel","middleware","deprecation","waituntil","edge-functions","build-warning"],"backgroundTag":"deprecated-file-based-hook","analyzedSha":"3578d45d34226d63cff3d261c971c221de6794d2","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}