@nx/esbuild: --output-path CLI override is ignored for the bundled entry file (getOutfile uses context.target.options.outputPath instead of normalized options)
Current Behavior
When running an @nx/esbuild:esbuild build for a "singleEntry + bundle" Node app and overriding the output directory via the --output-path CLI flag (or a target configuration that isn't the one baked into project.json), the bundled entry file (e.g. main.js) is written to the static outputPath configured in the project's project.json target — NOT to the overridden path.
Everything else in the same build (copied assets, generated package.json/lockfile via generatePackageJson) correctly respects the overridden --output-path. Only the actual JS bundle file ends up in the wrong directory.
This is a silent failure: the build exits 0, "Successfully ran target", and the override directory looks fully populated (assets, fixtures, package.json) — just missing the one file (main.js) that makes the output runnable. We only noticed because a Docker image built from the "overridden" output directory failed at runtime with Cannot find module './main.js'.
Root cause (traced in v23.2.1):
node_modules/@nx/esbuild/dist/src/executors/esbuild/lib/build-esbuild-options.js, function getOutfile:
function getOutfile(format, options, context) {
const ext = getOutExtension(format, options, context);
const candidate = joinPathFragments(context.target.options.outputPath, options.outputFileName);
...
}context.target.options.outputPath is the unmerged, static value from project.json for that target. It does not reflect a CLI --output-path override (or any override that isn't statically present in the target/configuration definition read from the project graph). Meanwhile copyAssets and copyPackageJson (called earlier in esbuild.impl.js) are passed the normalized options object, which does correctly include the override — hence the asset/package.json vs. bundle-file inconsistency.
Expected Behavior
When --output-path=<dir> (or any equivalent override) is passed on the CLI, ALL build outputs — including the bundled entry file computed via getOutfile — should be written to the overridden directory, consistent with where assets and the generated package.json are written.
At minimum, getOutfile should use the normalized options.outputPath (which reflects CLI/configuration overrides) instead of context.target.options.outputPath (the static project.json value).
GitHub Repo
No response
Steps to Reproduce
In an Nx workspace, create/use a Node app project with an
@nx/esbuild:esbuildbuild target configured roughly like:{ "targets": { "build-container": { "executor": "@nx/esbuild:esbuild", "options": { "platform": "node", "outputPath": "dist-a", "format": ["cjs"], "main": "apps/my-app/src/main.ts", "tsConfig": "apps/my-app/tsconfig.app.json", "generatePackageJson": true } } } }
Run the target with the default (static) outputPath and confirm
dist-a/main.jsis produced:npx nx build-container my-app --skip-nx-cache
Clean both directories, then run the SAME target but override the output path via CLI:
rm -rf dist-a dist-b npx nx build-container my-app --skip-nx-cache --output-path=dist-b
Inspect the results:
dist-b/contains assets andpackage.json(respects the override) but NOTmain.js.dist-a/main.jsexists instead — the bundle silently landed in the static project.json path, not the overridden one.
Nx Report
Node : 24.20.0
OS : win32-x64
Native Target : x86_64-windows
npm : 11.19.0
daemon : Available
nx : 23.2.1
@nx/js : 23.2.1
@nx/eslint : 23.2.1
@nx/workspace : 23.2.1
@nx/angular : 23.2.1
@nx/jest : 23.2.1
@nx/devkit : 23.2.1
@nx/esbuild : 23.2.1
@nx/eslint-plugin : 23.2.1
@nx/node : 23.2.1
@nx/vite : 23.2.1
@nx/vitest : 23.2.1
@nx/web : 23.2.1
@nx/webpack : 23.2.1
@nx/docker : 23.2.1
typescript : 6.0.3
---------------------------------------
Registered Plugins:
@nx/webpack/plugin
@nx/eslint/plugin
@nx/vite/plugin
@nx/vitest
@nx/jest/pluginFailure Logs
Package Manager Version
No response
Operating System
- macOS
- Linux
- Windows
- Other (Please specify)
Additional Information
No response
Source: nrwl/nx