vercel/pkg
Package your Node.js project into an executable
Healthy across all four use cases
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓26+ active contributors
- ✓Distributed ownership (top contributor 31% of recent commits)
- ✓MIT licensed
- ✓CI configured
- ✓Tests present
- ⚠Stale — last commit 2y ago
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the “Healthy” badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/vercel/pkg)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/vercel/pkg on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: vercel/pkg
Generated by RepoPilot · 2026-05-06 · Source
Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/vercel/pkg shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
Verdict
GO — Healthy across all four use cases
- 26+ active contributors
- Distributed ownership (top contributor 31% of recent commits)
- MIT licensed
- CI configured
- Tests present
- ⚠ Stale — last commit 2y ago
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live vercel/pkg
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/vercel/pkg.
What it runs against: a local clone of vercel/pkg — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in vercel/pkg | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 884 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of vercel/pkg. If you don't
# have one yet, run these first:
#
# git clone https://github.com/vercel/pkg.git
# cd pkg
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of vercel/pkg and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "vercel/pkg(\\.git)?\\b" \\
&& ok "origin remote is vercel/pkg" \\
|| miss "origin remote is not vercel/pkg (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "README.md" \\
&& ok "README.md" \\
|| miss "missing critical file: README.md"
test -f "package.json" \\
&& ok "package.json" \\
|| miss "missing critical file: package.json"
test -f ".github/workflows/ci.yml" \\
&& ok ".github/workflows/ci.yml" \\
|| miss "missing critical file: .github/workflows/ci.yml"
test -f ".eslintrc" \\
&& ok ".eslintrc" \\
|| miss "missing critical file: .eslintrc"
test -f "dictionary/" \\
&& ok "dictionary/" \\
|| miss "missing critical file: dictionary/"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 884 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~854d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/vercel/pkg"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
TL;DR
pkg is a command-line tool that bundles a Node.js application into a single executable binary that runs on Windows, macOS, and Linux without requiring Node.js to be installed. It compiles JavaScript to bytecode, embeds native dependencies, and can cross-compile for different target platforms—solving the distribution problem for CLI tools and servers by turning npm packages into portable, obfuscated executables. Single-package structure: the root contains the CLI entry point and core bundling logic, dictionary/ holds ESLint-verified module resolution rules for 60+ npm packages (e.g., aws-sdk.js, bcrypt.js handle native bindings), .github/workflows/ci.yml runs tests on commits, and language composition is 78% JavaScript / 22% TypeScript with some legacy CoffeeScript.
Who it's for
Node.js developers building CLI tools, commercial applications, or desktop software who need to distribute their work to end-users without exposing source code or requiring npm/Node.js installation on target machines.
Maturity & risk
pkg is deprecated as of v5.8.1 (the last release) and the repository is now archived. It was production-ready for years but is no longer maintained by Vercel; the team recommends using Node.js 21+'s native single-executable-applications feature instead. Despite deprecation, it remains widely used in existing projects.
Critical risk: the project is officially unmaintained and archived—no security patches or bug fixes will be released. The dictionary/ folder contains hardcoded module mappings (60+ files) that require manual updates for new packages, creating stale dependencies. Single maintainer (Vercel team) context means the fork ecosystem has fragmented into multiple maintained alternatives.
Active areas of work
Nothing—the project is archived. The final state is v5.8.1 with no active issues, PRs, or development. The repository remains open for reference and forks but receives no updates.
Get running
git clone https://github.com/vercel/pkg.git
cd pkg
yarn install
yarn test
Daily commands:
No development server. To package a Node.js project with pkg: pkg index.js (outputs for Linux/macOS/Windows), or pkg -t node16-linux,node18-win index.js for specific targets. For development, run yarn test to validate changes to the bundler.
Map of the codebase
README.md— Documents the deprecated status, use cases, and primary CLI interface—essential context that this tool is archived as of v5.8.1 and understanding its design intent.package.json— Defines pkg's own dependencies and configuration; critical for understanding the build system and deployment targets..github/workflows/ci.yml— Specifies the CI/CD pipeline for testing, building, and releasing pkg across multiple platforms—core for understanding how the tool itself is validated..eslintrc— Enforces code style across the 600-file codebase; breaking this affects all contributor submissions.dictionary/— Contains 120+ module shimming definitions for dynamic require() resolution during bundling—the largest single abstraction in the tool.
Components & responsibilities
- CLI & Argument Parsing (Node.js yargs/minimist, shell argument parsing) — Accept command-line arguments (--target, --output, --compress) and validate against supported platforms
- Failure mode: Invalid targets or missing required flags cause early exit with helpful error message
- Module Dictionary (JavaScript module definitions, CommonJS re-exports) — Provide shimmed versions of 120+ npm modules (express, aws-sdk, etc.) to enable bundling without full sources
- Failure mode: Missing dictionary entry for a dynamic require() causes bundle failure or runtime error; mitigated by warning messages
- Bundler & Snapshot Creator (Webpack/browserify-compatible require resolver, snapshot serialization) — Walk the require() tree starting from the entry point, collect source and assets, and create a V8 snapshot
- Failure mode: Circular dependencies or unresolvable requires stop the build; out-of-memory errors on very large projects
- Platform-Specific Compiler (nexe, native compiler toolchain (MSVC, clang, gcc)) — Invoke nexe to compile the Node.js binary with the embedded snapshot for Windows, macOS, and Linux
- Failure mode: Cross-compilation failures (e.g., missing cross-compiler) prevent binary generation for target platform; requires host machine setup
Data flow
Developer's package.json→CLI Config Parser— pkg configuration (targets, assets, entry point) flows to the CLICLI Config Parser→Bundler— Parsed config directs bundler to resolve and embed specified assetsSource code & node_modules→Bundler— Application code and transitive dependencies are walked via require() analysisBundler→Module Dictionary— Dynamic requires are looked up in the dictionary for shimmed replacementsBundler→Snapshot Creator— Resolved modules and assets are serialized into a V8 snapshot bytecodeSnapshot Creator & nexe→Compiler— Snapshot is injected into Node.js source; native compiler produces platform-specific binaryCompiler→Binary Artifact— Standalone executable (one file per platform) is written to disk
How to make changes
Add Support for a New npm Module
- Create a new shim file in the dictionary folder following the module name (
dictionary/new-module-name.js) - Implement the shim by exporting the module's public API (or a no-op if the module is not bundled) (
dictionary/new-module-name.js) - Test the shim with a project that depends on the module and pkg's bundling process (
.github/workflows/ci.yml)
Add a New Target Platform
- Update the pkg configuration in your project's package.json to include the new Node.js target version (
package.json) - Add test matrix entry to CI workflow for the new platform (
.github/workflows/ci.yml)
Include Static Assets in the Bundle
- Define the assets glob pattern in your project's pkg.assets configuration (
package.json) - Access bundled assets at runtime using the special __dirname and __filename bindings provided by pkg (
index.js)
Why these technologies
- nexe — Core compiler that embeds Node.js runtime and bundled application into a standalone native executable
- ESLint & Prettier — Ensures consistent code style and quality across 600 files and 120+ dictionary definitions
- GitHub Actions — Automated testing and release pipeline across Windows, macOS, and Linux platforms
- Webpack/browserify-compatible bundling — Resolves CommonJS dependencies and static assets for embedding in the binary
Trade-offs already made
-
Pre-built module dictionary instead of dynamic shimming
- Why: Provides explicit control over which modules can be bundled and prevents runtime resolution failures
- Consequence: Requires manual maintenance of 120+ module definitions; new modules need explicit dictionary entries
-
Single-file binary format with embedded snapshot
- Why: Eliminates need for Node.js installation and node_modules directory on target machines
- Consequence: Binary size increases significantly; unpacking at runtime adds startup latency
-
Cross-platform compilation from single host
- Why: Developers can generate Windows, macOS, and Linux binaries from any platform
- Consequence: Adds complexity to the compiler layer and test matrix; increases CI runtime
Non-goals (don't propose these)
- Real-time code reloading or hot module replacement
- Support for dynamic require() of arbitrary modules not in the dictionary
- License compliance or SBOM generation
- Active maintenance (deprecated as of v5.8.1; users should migrate to Node.js 21+ single-executable-applications)
Anti-patterns to avoid
- Deprecation without clear migration path (High) —
README.md: Tool is marked deprecated (v5.8.1 last release) but extensive dictionary and CI infrastructure remain; users may not immediately find the recommended Node.js 21+ single-executable-applications alternative - Manual module dictionary maintenance (Medium) —
dictionary/: 120+ module shims are hand-maintained; new npm packages require manual dictionary entry, creating scalability friction and stale definitions - Lack of visible error recovery in bundling (Medium) —
dictionary/: Missing dictionary entries for dynamic requires may fail silently or at runtime rather than during build; no clear UX for diagnosing bundling failures
Performance hotspots
dictionary/ (120+ files)(Scalability & Maintenance) — Module shimming layer is the largest single source of maintenance burden; each new npm package may require a custom definition.github/workflows/ci.yml(Performance & Infrastructure) — Cross-platform compilation (Windows, macOS, Linux) multiplies test matrix size and CI runtime; nexe compilation is inherently slow (~minutes per target)require() resolution during bundling(Architectural Constraint) — Dynamic requires must be statically analyzable; non-standard patterns (computed paths, circular deps) break the bundler
Traps & gotchas
The dictionary/ folder is critical for dependency resolution—missing or outdated entries cause bundling failures for packages with native bindings. The project uses Yarn (.yarnrc present), not npm, so yarn install is required, not npm install. Platform-specific base binaries are downloaded by default; use --build flag to compile from source locally (slow, requires build tools). The --no-dict flag can disable dictionary lookups entirely, but this breaks bundling for packages like bcrypt or aws-sdk. Bytecode generation is on by default—use --no-bytecode to include plain JavaScript (larger output, source visible). macOS binaries require code signing by default; use --no-signature to skip (disabled on non-macOS).
Architecture
Related repos
nexe/nexe— Direct competitor in the Node.js-to-executable space with similar cross-compilation goals but different implementation and active maintenancekaiaulu/caxa— Alternative tool for bundling Node.js applications into standalone executables, maintained fork/successor addressing pkg's deprecationvercel/ncc— Companion tool from Vercel for bundling Node.js dependencies into a single file (used for GitHub Actions, precursor to pkg for simpler use cases)nodejs/node— The official Node.js repository now includes native single-executable-applications support (Node.js 21+), the technology Vercel recommends as pkg's replacementelectron/electron— Related ecosystem for packaging desktop Node.js applications, though targets a different use case (GUI apps vs. CLI/server binaries)
PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive dictionary entry tests for native module bindings
The dictionary/ folder contains 60+ module override files (bcrypt.js, better-sqlite3.js, bindings.js, etc.) but there are no visible tests validating these dictionary entries work correctly. This is critical because incorrect dictionary entries can break the packaging of common modules. New contributors could add unit tests that verify each dictionary entry properly handles module resolution, native binding paths, and asset inclusion.
- [ ] Create test/dictionary/ directory with test suite
- [ ] Add tests that verify each dictionary/*.js file exports valid configuration
- [ ] Test that dictionary entries for native modules (bcrypt.js, better-sqlite3.js, epoll.js, etc.) correctly handle binary paths
- [ ] Add CI step in .github/workflows/ci.yml to run dictionary tests on every PR
Create integration tests for pkg config file parsing (pkg object in package.json)
The README and package.json examples show the 'pkg' configuration object with 'assets' and 'targets' fields, but there are no visible tests validating that the pkg configuration parser correctly handles various edge cases, invalid inputs, and conflicting options. This is crucial since misconfigured pkg objects lead to silent failures.
- [ ] Create test/config/ directory with configuration parsing tests
- [ ] Add tests for pkg.assets path resolution (glob patterns, relative paths, invalid paths)
- [ ] Add tests for pkg.targets validation (valid node versions, invalid formats)
- [ ] Add tests for conflicting pkg configurations and error messaging
- [ ] Reference the Dependencies/Config snippet structure in tests
Add platform-specific cross-compilation validation tests
The README highlights cross-compilation as a key use case ('Instantly make executables for other platforms'), but there are no visible tests validating that the tool correctly handles building for different target platforms (linux, macos, windows) and architectures. This is high-value because cross-compilation failures are platform-specific and hard to debug.
- [ ] Create test/cross-compile/ directory
- [ ] Add tests validating target platform detection and validation in .github/workflows/ci.yml or create new workflow
- [ ] Add tests for architecture-specific asset handling (exe files like dictionary/exiftool.exe.js)
- [ ] Add tests for Windows-specific considerations (path separators, .exe extensions) since dictionary has exiftool.exe.js entries
Good first issues
- The
dictionary/folder has 60+ hardcoded module mappings maintained manually. Create or improve entries for popular native packages (node-sqlite, node-gyp packages) following the pattern of existing.jsfiles, adding unit tests in.github/workflows/ci.ymlto validate new entries. - Add TypeScript definitions (
*.d.tsfiles) for the main CLI entry point and exported bundler API, since the project has 22% TypeScript but lacks type coverage—beneficial for downstream pkg-based tooling. - Document the internal module resolution algorithm and dictionary format in a
CONTRIBUTING.mdfile with examples for how to add support for a new native npm package, lowering the barrier for community contributions to dictionary maintenance.
Top contributors
- @jesec — 31 commits
- @leerob — 16 commits
- @robertsLando — 8 commits
- @ignatiusmb — 7 commits
- @dependabot[bot] — 6 commits
Recent commits
9066cee— Deprecatepkg. (leerob)bb04269— build(deps): bump semver from 6.3.0 to 6.3.1 (#1958) (dependabot[bot])ace66be— build(deps): bump word-wrap from 1.2.3 to 1.2.4 (#1965) (dependabot[bot])73a03d1— fix: missing entrypoint when launched from self-created child process (#1949) (Luzzifus)e51efbe— fix: Add missing functions from restored fs.Stats (#1923) (phated)76010f6— chore: bump pkg-fetch to 3.5.2 (#1914) (dav-is)7255f64— test: ignore pnpm test for node14 (#1919) (emmansun)c353cc9— chore: remove unused dependencies (#1769) (ignatiusmb)265c00e— test: update tesseract.js test for v4 (#1864) (some1chan)4fe0b4d— chore: remove eol nodejs in tests (#1889) (Corentin Mors)
Security observations
The codebase presents significant security concerns primarily due to the use of a deprecated and unmaintained tool (pkg) combined with an extremely outdated Express dependency (4.15.2 from 2017). The project appears to be an example or demonstration rather than production code. The security posture is poor: there are no visible security headers, input validation, or modern dependency management practices. Immediate action is required to update dependencies and consider migration to actively maintained alternatives. The deprecation status of pkg itself is a critical concern for long-term security and compatibility.
- High · Outdated Express Dependency —
package.json - dependencies.express. The package.json specifies Express 4.15.2, which was released in April 2017 and contains multiple known security vulnerabilities including denial of service and potential code execution issues. This version is significantly outdated. Fix: Update Express to the latest stable version (4.18.x or 5.x). Run 'npm install express@latest' and test compatibility. - High · Deprecated Project - No Active Maintenance —
README.md. The README explicitly states thatpkghas been deprecated as of version 5.8.1 and is no longer actively maintained. This means security vulnerabilities will not be patched, and the tool may become incompatible with future Node.js versions. Fix: Consider migrating to Node.js 21+ native single executable applications feature, or use an actively maintained fork of pkg. - Medium · Lack of Input Validation in Asset Globbing —
package.json - pkg.assets. The pkg configuration uses glob patterns for assets ('views/**/*') without apparent validation. This could potentially include unintended files or sensitive data if directory structure is not carefully managed. Fix: Explicitly specify asset paths and regularly audit bundled files. Consider using a whitelist approach and avoid overly broad glob patterns. - Medium · Missing Security Headers Configuration —
package.json - example configuration. The Express example configuration shown does not include essential security middleware such as helmet.js for setting HTTP security headers, CORS configuration validation, or rate limiting. Fix: Implement security middleware: install 'helmet' and configure it. Add CORS restrictions, rate limiting, and content security policies appropriate for your use case. - Low · No Supply Chain Security Verification —
.yarnrc and package management. The repository structure shows numerous dictionary files (node_modules shimming) without apparent integrity verification or lock file enforcement visible in the configuration. Fix: Ensure yarn.lock or package-lock.json is committed to version control. Consider using npm audit regularly and implementing dependency scanning in CI/CD pipeline.
LLM-derived; treat as a starting point, not a security audit.
Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.