
Fix Next.js 16.3 next-server.js.nft.json ENOENT on Vercel
Use one Next.js config for Vercel and standalone Docker builds, understand the 16.3 trace-file regression, and verify both deployment paths safely.
If a Next.js 16.3 deployment compiles successfully on Vercel and then fails in onBuildComplete because .next/next-server.js.nft.json is missing, keep standalone output for the builds that use it and disable it only on Vercel. This guide gives you the config change, explains why it works, and shows how to test both deployment paths.
The fix
Change next.config.ts so Vercel uses the platform adapter without also asking Next.js to create a standalone server:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: process.env.VERCEL ? undefined : "standalone",
};
export default nextConfig;Commit that change and redeploy. Vercel documents VERCEL as a system environment variable available during the build, with the value 1. Vercel system environment variable reference
This keeps output: "standalone" for Docker or another self-hosted target, where Next.js creates a minimal server and copies the traced runtime files into .next/standalone. The official deployment guide describes standalone output as the Docker-oriented option. Next.js deployment options Next.js output reference
Confirm that this is your failure
Use this workaround when all of these conditions match:
- The project uses Next.js 16.3.0 or a 16.3.1 canary affected by the open report.
- The Vercel build finishes compilation and page generation before failing during onBuildComplete.
- The error is ENOENT for .next/next-server.js.nft.json.
- next.config.js or next.config.ts sets output to standalone.
The upstream issue has a minimal reproduction and reports that the same config succeeds on Next.js 16.2.11 and in a local 16.3 build without Vercel's adapter. An independent reporter reproduced the exact failure and confirmed the conditional config resolves it.
Running onBuildComplete from Vercel
Error: ENOENT: no such file or directory, open
'/vercel/path0/.next/next-server.js.nft.json'If your error says Module Factory Is Not Available, stop here. That is a separate Turbopack HMR problem covered in the loke.dev Module Factory diagnostic guide.
Why Next.js 16.3 reaches this state
The following is a source-backed analysis of the current 16.3.0 code, not a published maintainer root-cause statement.
A Next.js change merged in May made adapter builds skip the two whole-server trace files because adapters do not consume them. That change shipped in the 16.3 line. Upstream change #93684 Next.js 16.3.0 release
In the tagged Rust source, next_server_nft_assets returns an empty asset list when an adapter is active. This happens before the function checks whether standalone output is enabled. Tagged 16.3.0 trace-generation source
The standalone finalizer still calls handleTraceFiles for next-server.js.nft.json without a fallback. The build runs adapter finalization first and standalone finalization next. With both modes active, the producer skips the file and the standalone consumer tries to read it. Standalone trace copy in 16.3.0 Finalizer order in 16.3.0
That sequence explains the late failure: the application code has already compiled, but packaging the deployment output has not completed.
Why the conditional config is the narrow workaround
Vercel's Next.js integration already produces platform-specific deployment output. The standalone directory is for a different consumer: the container or Node.js host that starts the generated server.js. Selecting the output mode at build time avoids combining two finalizers that currently disagree about the whole-server trace.
A separate project merged this exact split on August 6. Its verification covered a 195-page Vercel-mode build with no standalone directory and a non-Vercel build that produced the expected standalone server. This downstream result is useful implementation evidence; framework behavior claims in this guide remain tied to Next.js and Vercel sources.
Verify both targets
1. Check the Vercel branch locally
This command tests your config selection. It does not reproduce Vercel's private build adapter by itself.
VERCEL=1 pnpm build
test ! -d .next/standaloneThe build should pass and the standalone directory should be absent. Then create a Vercel preview deployment. The preview is the real check that onBuildComplete finishes on the platform.
2. Check the Docker or self-hosted branch
Run a clean build without VERCEL in the environment:
rm -rf .next
env -u VERCEL pnpm build
test -d .next/standaloneStart the generated server using the path your project produces. A single-package app normally uses:
node .next/standalone/server.jsIn a monorepo, the server can be nested under the workspace path, such as .next/standalone/apps/web/server.js. Inspect the generated directory instead of assuming the single-package path. Also copy public and .next/static if your container build does not already do so; the official output reference notes that standalone generation does not copy those folders automatically.
3. Exercise a real route
A successful build is necessary but not sufficient. Start the container image and request at least one dynamic route, one static asset, and an image route if the app uses next/image. This catches missing runtime files and Docker copy-stage mistakes.
Do not mask the missing trace
Several tempting changes either target a different problem or can hide a broken artifact:
- Changing outputFileTracingRoot: that option changes the monorepo tracing boundary. An independent reproduction in the upstream issue reports that setting it explicitly did not change this ENOENT.
- Clearing .next: a clean build is useful for verification, but the Vercel failure is deterministic with the affected mode combination.
- Catching or ignoring the missing file: the standalone copier needs the whole-server trace to collect runtime dependencies. Treating ENOENT as a warning can leave a server that builds but cannot start.
- Setting NEXT_ADAPTER_PATH yourself: this is an internal adapter control, not the stable public switch for choosing your deployment output. Keep the workaround in next.config and remove it after an upstream fix is released.
Fallback: pin the previous minor
If one immutable config must always emit standalone output and cannot branch on the build target, pin Next.js 16.2.11 while the issue remains open:
pnpm add --save-exact next@16.2.11Commit the lockfile and run the application test suite plus both deployment builds. Do not use a range such as ^16.2.11 for a temporary pin, because it permits a later 16.x release.
When to remove the workaround
Track the upstream issue and remove the conditional only after all three checks pass:
- A Next.js release note or merged fix explicitly addresses adapter plus standalone output.
- The fixed version is installed exactly and the lockfile contains it.
- A Vercel preview build and a self-hosted standalone build both pass.
As of August 6, 2026, npm's stable next tag is 16.3.0, the issue is open, and its timeline does not link an upstream fix. The conditional config is therefore a temporary compatibility boundary, not a permanent Next.js deployment pattern.
Source checklist
- Primary: Next.js 16.3.0 tagged source, release, output documentation, and deployment documentation.
- Primary: Vercel system environment variable documentation for the build-time VERCEL flag.
- Pain and reproduction evidence: the open Next.js issue and its independent confirmations.
- Implementation evidence: the merged downstream regression test and two-mode build verification.