Did you read the migration guide?
Is there an existing issue that is already proposing this?
Potential Commit/PR that introduced the regression
PR #3313
Versions
11.0.17 → 11.0.18
Describe the regression
Description, and workaround generated by an IA.
The workaround resolves our issue, but I think there is still a bug on your end.
nest start hangs indefinitely when the child process exits on its own (e.g. process.exit(0)).
I use process.exit(0) after microservice initialization to validate startup in a CI pipeline. The startup test works fine on sub-apps that have no watchAssets configured, but hangs on apps where root-level compilerOptions.assets with watchAssets: true are inherited — even though the asset globs don't match any files for that sub-app.
Works on 11.0.17, hangs on 11.0.18+.
Running with node dist/main.js always exits correctly. Only nest start hangs.
Root cause
In 11.0.18, closeWatchers() in assets-manager.js was changed from a setTimeout-based approach to Promise.all(watcherReadyPromises).then(close).
When an asset glob with watchAssets: true matches no files (common in monorepos where root-level assets don't exist in every sub-app's sourceRoot), glob.sync() returns [] and chokidar.watch([]) never emits 'ready'. This blocks Promise.all() from ever resolving, so all FSWatchers — including ones watching real files — are never closed. The parent process hangs.
Workaround
Move compilerOptions.assets from the root config to each project's own compilerOptions in nest-cli.json, so that only apps that actually have those files get the watchers. This avoids the empty glob scenario.
Suggested fix
Skip watcher creation when the glob matches nothing:
const matchedPaths = glob.sync(item.glob, { ignore: item.exclude, dot: true });
if (matchedPaths.length === 0) return; // chokidar.watch([]) never emits 'ready'
const watcher = chokidar.watch(matchedPaths)...
Minimum reproduction code
// nest-cli.json — one glob matches files, the other matches nothing
{
"sourceRoot": "src",
"compilerOptions": {
"assets": [
{ "include": "i18n/**/*.json", "watchAssets": true, "outDir": "dist/src" },
{ "include": "templates/**/*", "watchAssets": true, "outDir": "dist/src" }
]
}
}
// src/templates/page.html exists → creates real FSWatcher handles
// src/i18n/ does NOT exist → chokidar.watch([]) → 'ready' never fires → Promise.all blocks
// main.ts — app that exits after startup (CI startup validation)
const app = await NestFactory.create(AppModule);
await app.listen(0);
await app.close();
process.exit(0);
node dist/main.js → exits immediately
nest start → hangs forever
Expected behavior
nest start should exit when the child process exits, regardless of whether some asset globs match no files.
Other
Node.js: v22.22.0
OS: Linux
Works on 11.0.17, broken on 11.0.18
Did you read the migration guide?
Is there an existing issue that is already proposing this?
Potential Commit/PR that introduced the regression
PR #3313
Versions
11.0.17 → 11.0.18
Describe the regression
Description, and workaround generated by an IA.
The workaround resolves our issue, but I think there is still a bug on your end.
nest starthangs indefinitely when the child process exits on its own (e.g.process.exit(0)).I use
process.exit(0)after microservice initialization to validate startup in a CI pipeline. The startup test works fine on sub-apps that have nowatchAssetsconfigured, but hangs on apps where root-levelcompilerOptions.assetswithwatchAssets: trueare inherited — even though the asset globs don't match any files for that sub-app.Works on 11.0.17, hangs on 11.0.18+.
Running with
node dist/main.jsalways exits correctly. Onlynest starthangs.Root cause
In 11.0.18,
closeWatchers()inassets-manager.jswas changed from asetTimeout-based approach toPromise.all(watcherReadyPromises).then(close).When an asset glob with
watchAssets: truematches no files (common in monorepos where root-level assets don't exist in every sub-app'ssourceRoot),glob.sync()returns[]andchokidar.watch([])never emits'ready'. This blocksPromise.all()from ever resolving, so all FSWatchers — including ones watching real files — are never closed. The parent process hangs.Workaround
Move
compilerOptions.assetsfrom the root config to each project's owncompilerOptionsinnest-cli.json, so that only apps that actually have those files get the watchers. This avoids the empty glob scenario.Suggested fix
Skip watcher creation when the glob matches nothing:
Minimum reproduction code
node dist/main.js→ exits immediatelynest start→ hangs foreverExpected behavior
nest startshould exit when the child process exits, regardless of whether some asset globs match no files.Other
Node.js: v22.22.0
OS: Linux
Works on 11.0.17, broken on 11.0.18