Repository navigation
Description
varlock version
varlock 1.18.0 and @varlock/nextjs-integration 1.2.2, installed as @next/env through npm overrides as the docs describe. The watcher code is unchanged in 1.2.5 and on main (packages/integrations/nextjs/src/next-env-compat.ts, fs.watchFile in enableExtraFileWatchers).
Steps to reproduce
- Set up a Next.js 16 app (16.3.8 here) with
@next/envoverridden to@varlock/nextjs-integrationandvarlockNextConfigPlugin()innext.config. - Run
next dev, load any page, then stop it with Ctrl+C. - Run
pgrep -fl detached-flush. Next's telemetry helper (next/dist/telemetry/detached-flush.js), whichnext devspawns when it stops, is still running a minute later and never exits.
A shorter reproduction without a dev server, from the app directory:
mkdir -p .next/dev && echo '[]' > .next/dev/_events_repro.json
NEXT_TELEMETRY_DISABLED=1 node node_modules/next/dist/telemetry/detached-flush.js dev . _events_repro.jsonThe helper consumes the events file and then keeps running.
What is expected?
After next dev stops, the telemetry helper sends its events and exits.
What is actually happening?
The helper never exits, so every next dev stop leaves one Node process behind. One developer laptop had 24 of them, some two days old.
- Since Next 16.0.3 the helper no longer calls
process.exit; it exits when nothing is pending (vercel/next.js#97716). - The helper loads
next.configthrough Next'sloadConfigfor the development phase, which callsloadEnvConfig(dir, true). Innext-env-compat, that callsenableExtraFileWatchers, which startsfs.watchFile(filePath, { interval: 500 }, …)for.env.schemaand the other sources.fs.watchFilewatchers are persistent by default, so they keep the helper alive. claimExtraFileWatcherOwnershipdoesn't stop this. Thenext devparent process that spawns the helper never loads the env, so__VARLOCK_NEXT_ENV_WATCHER_PIDis not set in the helper's environment, and the helper claims the watchers.- An
async_hooksdump of a stuck helper showsprocess.getActiveResourcesInfo()as["StatWatcher","StatWatcher","StatWatcher"]. All three were created byenableExtraFileWatchers, called fromloadEnvConfig, Next'sloadConfigImplanddetached-flush.js. NEXT_TELEMETRY_DISABLED=1doesn't help, because Next spawns the helper anyway.
Suggested fix
Make the watchers non-persistent: fs.watchFile(filePath, { interval: 500, persistent: false }, …). persistent: false only stops a watcher from keeping the process alive. The dev server stays alive through its HTTP server, so env reloading keeps working, and short-lived processes such as the telemetry helper can exit. Calling unref() on the returned watcher would have the same effect.
System Info
macOS 27.0.1 (arm64) and Debian 12 (x64, in a container)
Node 24.14.0, npm 11.6.2
next 16.3.8
varlock 1.18.0, @varlock/nextjs-integration 1.2.2Any additional comments?
As a workaround, each next.config checks whether process.argv[1] ends with telemetry/detached-flush.js. If it does, the config schedules an unref'd process.exit(0) after 30 s. A non-persistent watcher would make that unnecessary.
Activity
pullfrog commentedon Oct 16, 2026
theoephraim commentedon Oct 16, 2026
thanks for the report!
Make Next.js extra env file watchers non-persistent (#1235) (#1237)
github-actions commentedon Oct 16, 2026
✅ A fix has been merged to
mainin #1237 and will ship in the next release. GitHub auto-closed this issue on merge, but the change isn't published yet.