Skip to content

@nx/esbuild: --output-path CLI override is ignored for the bundled entry file (getOutfile uses context.target.options.outputPath instead of normalized options) #37091

Description

@VijaySunder

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

  1. In an Nx workspace, create/use a Node app project with an @nx/esbuild:esbuild build 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
    }
    }
    }
    }

  2. Run the target with the default (static) outputPath and confirm dist-a/main.js is produced:

    npx nx build-container my-app --skip-nx-cache

  3. 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

  4. Inspect the results:

    • dist-b/ contains assets and package.json (respects the override) but NOT main.js.
    • dist-a/main.js exists 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/plugin

Failure Logs

Package Manager Version

No response

Operating System

  • macOS
  • Linux
  • Windows
  • Other (Please specify)

Additional Information

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions