experimental.adapterPath
Next.js provides an experimental API that allows you to create custom adapters to hook into the build process. This is useful for deployment platforms or custom build integrations that need to modify the Next.js configuration or process the build output.
Configuration
To use an adapter, specify the path to your adapter module in experimental.adapterPath
:
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
adapterPath: require.resolve('./my-adapter.js'),
},
}
module.exports = nextConfig
Creating an Adapter
An adapter is a module that exports an object implementing the NextAdapter
interface:
export interface NextAdapter {
name: string
modifyConfig?: (
config: NextConfigComplete,
ctx: {
phase: PHASE_TYPE
}
) => Promise<NextConfigComplete> | NextConfigComplete
onBuildComplete?: (ctx: {
routes: {
headers: Array<ManifestHeaderRoute>
redirects: Array<ManifestRedirectRoute>
rewrites: {
beforeFiles: Array<ManifestRewriteRoute>
afterFiles: Array<ManifestRewriteRoute>
fallback: Array<ManifestRewriteRoute>
}
dynamicRoutes: ReadonlyArray<ManifestRoute>
}
outputs: AdapterOutputs
projectDir: string
repoRoot: string
distDir: string
config: NextConfigComplete
nextVersion: string
}) => Promise<void> | void
}
Basic Adapter Structure
Here's a minimal adapter example:
/** @type {import('next').NextAdapter} */
const adapter = {
name: 'my-custom-adapter',
async modifyConfig(config, { phase }) {
// Modify the Next.js config based on the build phase
if (phase === 'phase-production-build') {
return {
...config,
// Add your modifications
}
}
return config
},
async onBuildComplete({
routes,
outputs,
projectDir,
repoRoot,
distDir,
config,
nextVersion,
}) {
// Process the build output
console.log('Build completed with', outputs.pages.length, 'pages')
// Access different output types
for (const page of outputs.pages) {
console.log('Page:', page.pathname, 'at', page.filePath)
}
for (const apiRoute of outputs.pagesApi) {
console.log('API Route:', apiRoute.pathname, 'at', apiRoute.filePath)
}
for (const appPage of outputs.appPages) {
console.log('App Page:', appPage.pathname, 'at', appPage.filePath)
}
for (const prerender of outputs.prerenders) {
console.log('Prerendered:', prerender.pathname)
}
},
}
module.exports = adapter
API Reference
modifyConfig(config, context)
Called for any CLI command that loads the next.config to allow modification of the configuration.
Parameters:
config
: The complete Next.js configuration objectcontext.phase
: The current build phase (see phases)
Returns: The modified configuration object (can be async)
onBuildComplete(context)
Called after the build process completes with detailed information about routes and outputs.
Parameters:
routes
: Object containing route manifests for headers, redirects, rewrites, and dynamic routesoutputs
: Detailed information about all build outputs organized by typeprojectDir
: Absolute path to the Next.js project directoryrepoRoot
: Absolute path to the detected repository rootdistDir
: Absolute path to the build output directoryconfig
: The final Next.js configuration (withmodifyConfig
applied)nextVersion
: Version of Next.js being used
Output Types
The outputs
object contains arrays of different output types:
Pages (outputs.pages
)
React pages from the pages/
directory:
{
type: 'PAGES'
id: string // Route identifier
filePath: string // Path to the built file
pathname: string // URL pathname
runtime: 'nodejs' | 'edge'
assets: Record<string, string> // Traced dependencies
config: {
maxDuration?: number
preferredRegion?: string | string[]
}
}
API Routes (outputs.pagesApi
)
API routes from pages/api/
:
{
type: 'PAGES_API'
id: string
filePath: string
pathname: string
runtime: 'nodejs' | 'edge'
assets: Record<string, string>
config: {
maxDuration?: number
preferredRegion?: string | string[]
}
}
App Pages (outputs.appPages
)
React pages from the app/
directory with page.{js,ts,jsx,tsx}
:
{
type: 'APP_PAGE'
id: string
filePath: string
pathname: string
runtime: 'nodejs' | 'edge'
assets: Record<string, string>
config: {
maxDuration?: number
preferredRegion?: string | string[]
}
}
App Routes (outputs.appRoutes
)
API and metadata routes from app/
with route.{js,ts,jsx,tsx}
:
{
type: 'APP_ROUTE'
// ... same structure as APP_PAGE
}
Prerenders (outputs.prerenders
)
ISR-enabled routes and static prerenders:
{
type: 'PRERENDER'
id: string
pathname: string
parentOutputId: string // ID of the source page/route
groupId: number // Revalidation group identifier
fallback?: {
filePath: string
initialStatus?: number
initialHeaders?: Record<string, string | string[]>
initialExpiration?: number
initialRevalidate?: number
postponedState?: string // PPR postponed state
}
config: {
allowQuery?: string[] // Allowed query parameters
allowHeader?: string[] // Allowed headers for ISR
bypassFor?: RouteHas[] // Cache bypass conditions
renderingMode?: RenderingMode
bypassToken?: string
}
}
Static Files (outputs.staticFiles
)
Static assets and auto-statically optimized pages:
{
type: 'STATIC_FILE'
id: string
filePath: string
pathname: string
}
Middleware (outputs.middleware
)
Middleware function (if present):
{
type: 'MIDDLEWARE'
id: string
filePath: string
pathname: string
runtime: 'nodejs' | 'edge'
assets: Record<string, string>
config: {
maxDuration?: number
preferredRegion?: string | string[]
matchers?: MiddlewareMatcher[]
}
}
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
Was this helpful?