adapterPath
Configure a custom adapter for Next.js to hook into the build process.
Next.js provides a built-in adapters API. It allows deployment platforms or build systems to integrate with the Next.js build process.
For a full reference implementation, see the nextjs/adapter-vercel adapter.
Configuration
To use an adapter, specify the path to your adapter module in adapterPath:
Alternatively NEXT_ADAPTER_PATH can be set to enable zero-config usage in deployment platforms.
Creating an Adapter
An adapter is a module that exports an object implementing the NextAdapter interface.
The interface can be imported from the next package:
The interface is defined as follows:
Basic Adapter Structure
Here's a minimal adapter example:
API Reference
async modifyConfig(config, context)
Called for any CLI command that loads the next.config.js file to allow modification of the configuration.
Parameters:
config: The complete Next.js configuration objectcontext.phase: The current build phase (see phases)context.nextVersion: Version of Next.js being used
Returns: The modified configuration object (can be async)
async onBuildComplete(context)
Called after the build process completes with detailed information about routes and outputs.
Parameters:
context.routing: Object containing Next.js routing phases and metadatarouting.beforeMiddleware: Routes executed before middleware (includes header and redirect handling)routing.beforeFiles: Rewrite routes checked before filesystem route matchingrouting.afterFiles: Rewrite routes checked after filesystem route matchingrouting.dynamicRoutes: Dynamic route matching tablerouting.onMatch: Routes applied after a successful match (for example immutable static asset cache headers)routing.fallback: Final rewrite fallback routesrouting.shouldNormalizeNextData: Whether/_next/data/<buildId>/...URLs should be normalized during matchingrouting.rsc: Route metadata used for React Server Components routing behavior
context.outputs: Detailed information about all build outputs organized by typecontext.projectDir: Absolute path to the Next.js project directorycontext.repoRoot: Absolute path to the detected repository rootcontext.distDir: Absolute path to the build output directorycontext.config: The final Next.js configuration (withmodifyConfigapplied)context.nextVersion: Version of Next.js being usedcontext.buildId: Unique identifier for the current build
Testing Adapters
Next.js provides a test harness for validating adapters. Running the end-to-end tests for deployment.
Example GitHub Actions workflow:
The test harness looks for these environment variables:
NEXT_TEST_DEPLOY_SCRIPT_PATH: Path to the executable that builds and deploys the isolated test appNEXT_TEST_DEPLOY_LOGS_SCRIPT_PATH: Path to the executable that returns build and runtime logs for that deploymentNEXT_TEST_CLEANUP_SCRIPT_PATH: Path to the optional executable that tears the deployment down after the test run
Custom deploy script contract
The deploy script NEXT_TEST_DEPLOY_SCRIPT_PATH is executed with cwd set to the isolated temporary app created by the Next.js test harness.
The deploy script must follow this contract:
- Exit with a non-zero code on failure.
- Print the deployment URL to
stdout. This will be used to verify the deployment. Avoid writing anything else tostdout. - Write diagnostic output to
stderror to files inside the working directory.
Because the deploy script and logs script run as separate processes, any data you want to use later, such as build IDs or server logs, should be persisted to files inside the working directory.
Example deploy script:
Custom logs script contract
The logs script NEXT_TEST_DEPLOY_LOGS_SCRIPT_PATH is executed with cwd set to the isolated temporary app created by the Next.js test harness.
Additionally it receives NEXT_TEST_DIR and NEXT_TEST_DEPLOY_URL as environment variables.
Its output must include lines starting with:
BUILD_ID:DEPLOYMENT_ID:IMMUTABLE_ASSET_TOKEN:(use the valueundefinedif your adapter does not produce one)
After those markers, the logs script can print any additional build or server logs that would help debug failures.
One pattern is to have the deploy script write .adapter-build.log and .adapter-server.log, then have the logs script replay those files so the harness can extract the required markers. This is one option, each platform has different ways to get the logs.
Custom cleanup script contract
The cleanup script NEXT_TEST_CLEANUP_SCRIPT_PATH is executed with cwd set to the isolated temporary app created by the Next.js test harness.
Additionally it receives NEXT_TEST_DIR and NEXT_TEST_DEPLOY_URL as environment variables.
The cleanup script can be used to clean up any resources created by the deploy script. It runs after the tests have completed.
Routing with @next/routing
You can use @next/routing to reproduce Next.js route matching behavior with data from onBuildComplete.
[!NOTE]
@next/routing is experimental and will stabilize with the adapters API.
resolveRoutes() returns:
resolvedPathname: The route pathname selected by Next.js routing. For dynamic routes, this is the matched route template such as/blog/[slug].resolvedQuery: The final query after rewrites or middleware have added or replaced search params.invocationTarget: The concrete pathname and query to invoke for the matched route.
For example, if /blog/post-1?draft=1 matches /blog/[slug]?slug=post-1, resolvedPathname is /blog/[slug] while invocationTarget.pathname is /blog/post-1.
Implementing PPR in an Adapter
For partially prerendered app routes, onBuildComplete gives you the data needed to seed and resume PPR:
outputs.prerenders[].fallback.filePath: path to the generated fallback shell (for example HTML)outputs.prerenders[].fallback.postponedState: serialized postponed state used to resume rendering
1. Seed shell + postponed state at build time
2. Runtime flow: serve cached shell and resume in background
At request time, you can stream a single response that is the concatenation of:
- cached HTML shell stream
- resumed render stream (generated after invoking
handlerwith postponed state)
3. Update cache with requestMeta.onCacheEntryV2
requestMeta.onCacheEntryV2 is called when a response cache entry is looked up or generated. Use it to persist updated shell/postponed data.
[!NOTE]
requestMeta.onCacheEntrystill works, but is deprecated.- Prefer
requestMeta.onCacheEntryV2. - If your adapter uses an internal
onCacheCallbackabstraction, wire it torequestMeta.onCacheEntryV2.
Invoking Entrypoints
Build output entrypoints use a handler(..., ctx) interface, with runtime-specific request/response types.
Node.js runtime (runtime: 'nodejs')
Node.js entrypoints use the following interface:
When invoking Node.js entrypoints directly, adapters can pass helpers directly on requestMeta instead of relying on internals. Some of the supported fields are hostname,
revalidate, and render404:
Relevant files in the Next.js core:
packages/next/src/build/templates/app-page.tspackages/next/src/build/templates/app-route.ts- and
packages/next/src/build/templates/pages-api.ts
Edge runtime (runtime: 'edge')
Edge entrypoints use the following interface:
The shape is aligned around handler(..., ctx), but Node.js and Edge runtimes use different request/response primitives.
For outputs with runtime: 'edge', Next.js also provides output.edgeRuntime with the canonical metadata needed to invoke the entrypoint:
After your edge runtime loads and evaluates the chunks for modulePath, use entryKey to read the registered entry from the global edge entry registry (globalThis._ENTRIES), then invoke handlerExport from that entry:
Use edgeRuntime instead of deriving registry keys or handler names from filenames.
Relevant files in the Next.js core:
packages/next/src/build/templates/edge-ssr.tspackages/next/src/build/templates/edge-app-route.tspackages/next/src/build/templates/pages-edge-api.ts- and
packages/next/src/build/templates/middleware.ts
Output Types
The outputs object contains arrays of build output types:
outputs.pages: React pages from thepages/directoryoutputs.pagesApi: API routes frompages/api/outputs.appPages: React pages from theapp/directoryoutputs.appRoutes: API and metadata routes fromapp/outputs.prerenders: ISR-enabled routes and static prerendersoutputs.staticFiles: Static assets and auto-statically optimized pagesoutputs.middleware: Middleware function (if present)
Note: When config.output is set to 'export', only outputs.staticFiles is populated. All other arrays (pages, appPages, pagesApi, appRoutes, prerenders) will be empty since the entire application is exported as static files.
For any route output with runtime: 'edge', edgeRuntime is included and contains the canonical entry metadata for invoking that output in your edge runtime.
Pages (outputs.pages)
React pages from the pages/ directory:
API Routes (outputs.pagesApi)
API routes from pages/api/:
App Pages (outputs.appPages)
React pages from the app/ directory:
App Routes (outputs.appRoutes)
API and metadata routes from the app/ directory:
Prerenders (outputs.prerenders)
ISR-enabled routes and static prerenders:
Static Files (outputs.staticFiles)
Static assets and auto-statically optimized pages:
Middleware (outputs.middleware)
middleware.ts (.js/.ts) or proxy.ts (.js/.ts) function (if present):
Routing Information
The routing object in onBuildComplete provides complete routing information with processed patterns ready for deployment:
routing.beforeMiddleware
Routes applied before middleware execution. These include generated header and redirect behavior.
routing.beforeFiles
Rewrite routes checked before filesystem route matching.
routing.afterFiles
Rewrite routes checked after filesystem route matching.
routing.dynamicRoutes
Dynamic matchers generated from route segments such as [slug] and catch-all routes.
routing.onMatch
Routes that apply after a successful match, such as immutable cache headers for hashed static assets.
routing.fallback
Final rewrite routes checked when earlier phases did not produce a match.
Common Route Fields
Each route entry can include:
source: Original route pattern (optional for generated internal rules)sourceRegex: Compiled regex for matching requestsdestination: Internal destination or redirect destinationheaders: Headers to applyhas: Positive matching conditionsmissing: Negative matching conditionsstatus: Redirect status codepriority: Internal route priority flag
Use Cases
Common use cases for adapters include:
- Deployment Platform Integration: Automatically configure build outputs for specific hosting platforms
- Asset Processing: Transform or optimize build outputs
- Monitoring Integration: Collect build metrics and route information
- Custom Bundling: Package outputs in platform-specific formats
- Build Validation: Ensure outputs meet specific requirements
- Route Generation: Use processed route information to generate platform-specific routing configs