You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When package.json declares bin as a string, pkg builds a single executable. When it's an object ({ "foo": "./foo.js", "bar": "./bar.js" }), pkg silently picks only one entry — the one matching the package name, falling back to the first key:
// lib/index.tsif(bin[inputJsonName]){bin=bin[inputJsonName];}else{bin=bin[Object.keys(bin)[0]];// TODO multiple inputs to pkg them all?}
The TODO has been in the code for years. Packages with multiple CLIs (e.g. a server + a migration tool) currently need multiple invocations with --config overrides, which defeats zero-config auto-discovery (#238).
Proposal
When bin is an object and the user hasn't narrowed it via CLI, build one executable per entry. The binary name defaults to the object key; the output path defaults to outputPath/<key> (or the current --output template, with {name} substituted per entry).
Keep the single-binary path working for users who want one entry:
pkg . with object-form bin → all entries (new default)
pkg . --bin my-tool-admin → only that one
A top-level bin string on the CLI still refers to one entry
Legacy behavior (picking the first/name-matching entry) becomes opt-in via explicit --bin <key>.
Scope
Extend config resolution in lib/index.ts to accept an array of (name, entryPath) pairs instead of a single inputBin
Loop the existing single-binary build pipeline per entry; share the walker/bytecode cache across entries where paths overlap to avoid re-walking node_modules N times
Clarify output naming: {name} in --output templates should expand to the bin key, not the package name
Interaction with .pkgrc (feat: support a .pkgrc configuration file #238): a pkgrc may override bin entirely (string, array, or object); bin still comes from package.json when the pkgrc doesn't declare one
Document migration for users who relied on the old "first key wins" behavior
Out of scope
Per-entry targets / outputPath — keep the shared config shape for this pass
When
package.jsondeclaresbinas a string, pkg builds a single executable. When it's an object ({ "foo": "./foo.js", "bar": "./bar.js" }), pkg silently picks only one entry — the one matching the package name, falling back to the first key:The TODO has been in the code for years. Packages with multiple CLIs (e.g. a server + a migration tool) currently need multiple invocations with
--configoverrides, which defeats zero-config auto-discovery (#238).Proposal
When
binis an object and the user hasn't narrowed it via CLI, build one executable per entry. The binary name defaults to the object key; the output path defaults tooutputPath/<key>(or the current--outputtemplate, with{name}substituted per entry).{ "name": "my-tool", "bin": { "my-tool": "./cli.js", "my-tool-admin": "./admin.js" }, "pkg": { "targets": ["node22-linux-x64"], "outputPath": "dist" } }→
dist/my-tool-linux,dist/my-tool-admin-linux.Selecting a subset
Keep the single-binary path working for users who want one entry:
pkg .with object-formbin→ all entries (new default)pkg . --bin my-tool-admin→ only that onebinstring on the CLI still refers to one entryLegacy behavior (picking the first/name-matching entry) becomes opt-in via explicit
--bin <key>.Scope
lib/index.tsto accept an array of(name, entryPath)pairs instead of a singleinputBinnode_modulesN times{name}in--outputtemplates should expand to the bin key, not the package name.pkgrc(feat: support a .pkgrc configuration file #238): a pkgrc may overridebinentirely (string, array, or object);binstill comes frompackage.jsonwhen the pkgrc doesn't declare oneOut of scope
targets/outputPath— keep the shared config shape for this passpostBuildPart of #235