microsoft/napajs
Napa.js: a multi-threaded JavaScript runtime
Stale — last commit 4y ago
worst of 4 axesnon-standard license (Other); last commit was 4y ago
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.
- ✓34+ active contributors
- ✓Other licensed
- ✓CI configured
Show 4 more →Show less
- ✓Tests present
- ⚠Stale — last commit 4y ago
- ⚠Concentrated ownership — top contributor handles 50% of recent commits
- ⚠Non-standard license (Other) — review terms
What would change the summary?
- →Use as dependency Concerns → Mixed if: clarify license terms
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 "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/microsoft/napajs)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/microsoft/napajs on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: microsoft/napajs
Generated by RepoPilot · 2026-05-09 · 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/microsoft/napajs 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
WAIT — Stale — last commit 4y ago
- 34+ active contributors
- Other licensed
- CI configured
- Tests present
- ⚠ Stale — last commit 4y ago
- ⚠ Concentrated ownership — top contributor handles 50% of recent commits
- ⚠ Non-standard license (Other) — review terms
<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 microsoft/napajs
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/microsoft/napajs.
What it runs against: a local clone of microsoft/napajs — 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 microsoft/napajs | Confirms the artifact applies here, not a fork |
| 2 | License is still Other | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 1379 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of microsoft/napajs. If you don't
# have one yet, run these first:
#
# git clone https://github.com/microsoft/napajs.git
# cd napajs
#
# 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 microsoft/napajs and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "microsoft/napajs(\\.git)?\\b" \\
&& ok "origin remote is microsoft/napajs" \\
|| miss "origin remote is not microsoft/napajs (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
&& ok "license is Other" \\
|| miss "license drift — was Other at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "README.md" \\
&& ok "README.md" \\
|| miss "missing critical file: README.md"
test -f "CMakeLists.txt" \\
&& ok "CMakeLists.txt" \\
|| miss "missing critical file: CMakeLists.txt"
test -f "docs/architecture.png" \\
&& ok "docs/architecture.png" \\
|| miss "missing critical file: docs/architecture.png"
test -f "docs/api/zone.md" \\
&& ok "docs/api/zone.md" \\
|| miss "missing critical file: docs/api/zone.md"
test -f "docs/design/transport-js-builtins.md" \\
&& ok "docs/design/transport-js-builtins.md" \\
|| miss "missing critical file: docs/design/transport-js-builtins.md"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 1379 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~1349d)"
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/microsoft/napajs"
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
Napa.js is a multi-threaded JavaScript runtime built on V8 that executes JavaScript across multiple isolates (threads) with inter-thread communication APIs. It complements Node.js for CPU-bound tasks by enabling parallel execution of JavaScript code, originally developed at Microsoft to power Bing's iterative services. Core features include zone-based worker pools, object transportation/sharing, and synchronization primitives across threads. Hybrid monorepo structure: src/ contains TypeScript core runtime; examples/modules/ (hello-world, async-number) showcase integration patterns; benchmark/ provides scalability/overhead comparisons; docs/api/ documents zones, stores, transport, and sync APIs separately. C++ bindings (addon.cpp) bridge V8 isolates; CMakeLists.txt orchestrates native builds.
👥Who it's for
Backend engineers building CPU-intensive services in Node.js who need multi-threaded JavaScript execution without spawning child processes; developers at Microsoft/Bing originally, and teams needing high-performance parallel JavaScript (Monte Carlo simulations, matrix operations, data processing) that would otherwise require native modules or worker threads.
🌱Maturity & risk
Actively developed and production-ready: Travis CI and AppVeyor confirm continuous integration, npm package published with version tracking, comprehensive API documentation in docs/api/, and structured examples provided. However, limited recent GitHub activity suggests maintenance mode rather than active feature development.
Small but specialized dependency footprint (V8, native C++ bindings); Windows build support via appveyor.yml and build.bat shows fragmented platform coverage. Risk: native module compilation failure across platforms, V8 version lock-in (no version flexibility shown), and single-organization maintainership. The long TypeScript codebase (166K lines) means complexity concentration.
Active areas of work
Repository appears in maintenance mode. No milestone data provided, but structure suggests focus on example modules (hello-world, async-number with binding.gyp files) and benchmark coverage (execute-overhead.ts, transport-overhead.ts, store-overhead.ts) for performance validation. CI pipeline active (Travis, AppVeyor configs present).
🚀Get running
git clone https://github.com/microsoft/napajs.git
cd napajs
npm install
node build.js
Then explore examples in examples/modules/hello-world or run benchmarks: npm run benchmark (if script exists in root package.json).
Daily commands:
Build: node build.js or platform-specific build.bat (Windows). Development: npm install && npm run prepare (runs TypeScript compilation per package.json scripts). Run examples: cd examples/modules/hello-world && npm install && npm test (mocha-based tests). Benchmarks: inspect benchmark/*.ts files and execute via TypeScript runner.
🗺️Map of the codebase
README.md— Defines Napa.js as a multi-threaded V8 runtime for CPU-bound tasks in Node.js; essential for understanding project mission and capabilitiesCMakeLists.txt— Root build configuration for the C++ native runtime; required to understand compilation dependencies and module structuredocs/architecture.png— Visual architecture diagram showing Napa's multi-threaded design; critical reference for understanding component relationshipsdocs/api/zone.md— API documentation for zones (thread pools); zones are the fundamental execution unit in Napa.jsdocs/design/transport-js-builtins.md— Design document explaining inter-thread communication and data transport mechanisms; core to understanding Napa's concurrency modelbenchmark/bench.ts— Benchmark suite demonstrating performance characteristics and typical usage patternsbuild.js— Main build orchestration script that coordinates TypeScript compilation, C++ builds, and test execution
🧩Components & responsibilities
- Zone (Thread Pool) (C++, pthreads/Windows threads, V8 Isolate API) — Manages a group of worker threads with isolated V8 contexts; schedules and executes functions
- Failure mode: Zone exhaustion (all workers busy) causes queuing; potential deadlock if worker code blocks indefinitely
- Data Transport Layer (C++, JSON, V8 object serialization) — Serializes JavaScript objects to JSON/binary for inter-thread communication; deserializes results
- Failure mode: Serialization failure on non-JSON-compatible types; performance degradation on large data transfers
- V8 JavaScript Runtime (V8 Engine, JavaScript) — Executes JavaScript code in isolated contexts; enforces memory safety and GC per isolate
- Failure mode: Uncaught exceptions terminate worker thread; memory exhaustion in one isolate affects that thread only
- Native Module Wrapper (C++, V8 API, node-gyp) — Bridges JavaScript API to C++ implementations; provides node-gyp bindings
- Failure mode: Incorrect binding code can cause memory corruption; native crashes bring down entire process
🔀Data flow
Node.js Application→Zone API— Developer calls zone.execute() with function code and argumentsZone API→Data Transport— Arguments serialized to JSON/binary representationData Transport→Worker Thread Queue— Serialized work item enqueued for next available workerWorker Thread Queue→V8 Isolate— Function code and deserialized arguments provided to isolated JavaScript contextundefined→undefined— undefined
🛠️How to make changes
Create a new Napa example module
- Create module directory structure: examples/modules/your-module/ with lib/, napa/, test/ subdirectories and package.json (
examples/modules/plus-number/package.json) - Write TypeScript API wrapper in lib/your-module.ts exposing the module interface (
examples/modules/plus-number/lib/plus-number.ts) - Create C++ native addon in napa/addon.cpp using V8 bindings to wrap native functions (
examples/modules/plus-number/napa/addon.cpp) - Configure compilation with binding.gyp (for node-gyp) or CMakeLists.txt for cmake builds (
examples/modules/plus-number/binding.gyp) - Add TypeScript tests in test/test.ts and verify with npm test (
examples/modules/plus-number/test/test.ts)
Add a performance benchmark
- Create new benchmark file in benchmark/ directory following naming pattern: benchmark/your-benchmark.ts (
benchmark/execute-overhead.ts) - Import bench utilities and define benchmark configurations with min/max worker counts (
benchmark/bench-utils.ts) - Register benchmark in main benchmark runner by adding to benchmark/bench.ts imports and execution (
benchmark/bench.ts)
Extend Napa runtime capabilities
- Add new API documentation under docs/api/ describing the new capability (
docs/api/zone.md) - Create design rationale document in docs/design/ if the feature involves significant architectural changes (
docs/design/transport-js-builtins.md) - Update CMakeLists.txt to include new C++ source files in appropriate build targets (
CMakeLists.txt)
🔧Why these technologies
- V8 JavaScript Engine — Core runtime for executing JavaScript; chosen for performance and multi-isolate support to enable true parallelism
- C++ with node-gyp/CMake — Provides native performance for compute-intensive operations; allows binding to C/C++ libraries
- TypeScript — Type safety for the JavaScript API surface; compiled to JavaScript for distribution
- Thread pools (zones) — Abstracts OS thread management; allows scaling work across multiple cores without explicit thread management
⚖️Trade-offs already made
-
Multi-isolate vs single-threaded Node.js
- Why: Node.js single thread limits CPU-bound performance; Napa trades simplicity for parallelism
- Consequence: Requires explicit data serialization between threads; more complex debugging and testing
-
Zone-based API vs explicit threading
- Why: Hides thread management complexity from developers; zones provide automatic load balancing
- Consequence: Less fine-grained control over thread affinity; overhead of work queue management
-
JSON-compatible data transport
- Why: Simplifies inter-thread communication; leverages JavaScript built-ins
- Consequence: Cannot directly share complex objects; serialization overhead for large data structures
🚫Non-goals (don't propose these)
- Real-time guarantees or bounded latency (is multi-threaded JavaScript runtime, not RTOS)
- Distributed computing across machines (single-process multi-threading only)
- Shared mutable state between threads (thread-safe shared memory not provided)
- Automatic load balancing across heterogeneous workloads (assumes similar-cost tasks in a zone)
🪤Traps & gotchas
V8 version pinning: CMakeLists.txt likely locks a specific V8 version; upgrading requires careful ABI compatibility checks. Platform-specific builds: Windows requires build.bat + Visual Studio toolchain; Linux/macOS use CMake—local environment setup critical. TypeScript compilation order: prepare script must run before tests (npm run pretest depends on npm run prepare for type definitions). Native module compilation: npm install in example modules triggers node-gyp, which fails silently if build tools missing. No Docker setup: cross-platform development difficult without manual toolchain installation.
🏗️Architecture
💡Concepts to learn
- V8 Isolate — Napa.js multiplexes JavaScript threads by creating separate V8 isolates per worker; understanding isolate isolation is core to safe cross-thread communication
- Object Serialization / Transport — Objects cannot be shared directly between isolates; Napa.js's transport API serializes objects for IPC, requiring knowledge of what's portable
- Native Module Binding (node-gyp) — Examples use binding.gyp to bridge C++ and JavaScript; required for extending Napa.js with native code
- Work Stealing / Task Scheduling — Zone pools likely use work-stealing queues to distribute tasks fairly across idle workers; impacts scalability benchmarks
- Synchronization Primitives (Mutex, Spinlock) — docs/api/sync.md exposes cross-thread locks; critical for safe shared state in multi-threaded code
- JavaScript Context / Realm — Each V8 isolate has its own global context; broadcasting code vs. executing functions has different context implications
- Zero-Copy Transfer / Move Semantics — Transport API likely supports ownership transfer to avoid deep copies; critical for performance with large objects
🔗Related repos
nodejs/node— Node.js worker_threads module provides similar multi-threaded JavaScript; understanding Node's approach clarifies Napa.js's design decisionsv8/v8— Napa.js is built directly on V8; critical for understanding isolate lifecycle, GC behavior, and native binding patternsparro-nodo/parro— Alternative JavaScript parallelism framework; useful for comparing zone-based vs. actor-model approachesMicrosoft/LightGBM— Similar Microsoft project requiring multi-threaded C++ with JavaScript bindings; shares native module integration patterns
🪄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 transport layer unit tests (src/transport/)
The docs/design/transport-js-builtins.md file indicates a sophisticated transport mechanism for inter-thread communication, but there are no visible test files in the file structure for the transport module. This is critical for a multi-threaded runtime where serialization/deserialization bugs could cause silent data corruption. New contributors could add unit tests covering edge cases like circular references, typed arrays, and large message passing.
- [ ] Review docs/design/transport-js-builtins.md to understand transport protocol
- [ ] Create test/transport directory with test files for serialization/deserialization
- [ ] Add tests for: primitive types, objects, circular references, typed arrays, large payloads, error propagation
- [ ] Ensure tests run in both Node.js and Napa.js contexts to verify bidirectional correctness
- [ ] Update tsconfig.json for test compilation if needed
Migrate benchmark suite to use GitHub Actions (replace .travis.yml and appveyor.yml)
The repo still uses legacy Travis CI (.travis.yml) and AppVeyor (appveyor.yml) configurations. GitHub Actions is more integrated with GitHub, faster, and easier to maintain. The benchmark directory contains multiple performance tests that should be automated. This modernizes the CI/CD pipeline and makes performance regression detection easier.
- [ ] Create .github/workflows/benchmark.yml workflow that installs dependencies, builds the project, and runs benchmark/*.ts scripts
- [ ] Create .github/workflows/build-and-test.yml to replace Travis/AppVeyor for Linux/MacOS/Windows matrix builds
- [ ] Ensure workflow runs 'npm install', 'tsc -p benchmark', and executes benchmark/bench.ts and benchmark/execute-overhead.ts
- [ ] Add workflow_dispatch trigger to allow manual performance benchmark runs
- [ ] Add benchmark results to GitHub Actions artifacts for historical tracking
- [ ] Deprecate .travis.yml and appveyor.yml with comments pointing to new workflows
Add integration tests for example modules against the main napa.js API
The examples/modules directory contains three example modules (hello-world, async-number, plus-number), each with individual test files, but there are no integration tests verifying these examples work correctly with the main napajs API from the parent package. New contributors could create cross-module tests that exercise the zone/module loading patterns documented in docs/api/zone.md and docs/api/module.md.
- [ ] Create examples/integration-tests directory with test files
- [ ] Add tests that: import napajs, create a zone, load each example module, execute functions, and verify results
- [ ] Test both synchronous and asynchronous execution paths for async-number module
- [ ] Verify module isolation - run same module in multiple zones and confirm data isn't leaked
- [ ] Add pretest script in examples package.json that compiles all examples before running integration tests
- [ ] Document expected behavior in examples/integration-tests/README.md
🌿Good first issues
- Improve CMake documentation: Add comments to CMakeLists.txt explaining V8 version selection, compiler flags, and platform-specific paths (C++/CMake knowledge only needed)
- Add TypeScript strict mode: Migrate tsconfig.json files in benchmark/, examples/, and src/ to strict: true and fix resulting type errors (good for learning TS and codebase structure)
- Create hello-world Node.js comparison benchmark: Add benchmark/hello-world-comparison.ts that runs the same task in Node.js threads vs. Napa.js zones side-by-side (TypeScript + understanding of benchmark framework)
⭐Top contributors
Click to expand
Top contributors
- @fs-eire — 50 commits
- @helloshuangzi — 12 commits
- @daiyip — 5 commits
- [@Allen Yongshuang Wang](https://github.com/Allen Yongshuang Wang) — 2 commits
- @asibross — 2 commits
📝Recent commits
Click to expand
Recent commits
b38a238— Fixed 8 typo errors in the log.md files (#274) (Abhilash Tiwari)73460d2— Update zone.md (#273) (rosethornbush)7e934ec— Update READMEs for the examples and fixed some grammatical errors in transport.md (#272) (Ruturaj123)02eb70c— Made some fixes in transport-js-builtins.md (#271) (pujanm)ff42fcb— fixed typos (#270) (sunitasen)3e472ac— Fix small typos (#269) (hemirt)1546003— Change var to const in the README.md (#268) (Algram)4c8fd41— Fix some small typos (#267) (ohnx)aa3200e— Fix small typo (#266) (Raphael Miedl)7a6f354— Started sentence with 'A' instead of 'a'. (#264) (amiyaKT)
🔒Security observations
The Napa.js codebase demonstrates reasonable security practices but has moderate concerns around dependency management and native module compilation. Primary risks include: (1) loose version constraints without upper bounds that could introduce vulnerable dependencies, (2) native C++ module compilation without visible build verification or pre-built binaries, and (3) outdated TypeScript versions. The codebase lacks formal security documentation (SECURITY.md) and vulnerability disclosure policies. No evidence of hardcoded credentials, injection vulnerabilities, or infrastructure misconfigurations was found. Recommend implementing stricter dependency pinning, providing pre-built binaries, updating development tooling, and establishing a security policy.
- Medium · Insecure Dependency Version Specification —
examples/modules/async-number/package.json. The package.json uses loose version constraints ('>= 0.1.2' for napajs, '>= 3.4.2' for mocha) without upper bounds. This allows installation of potentially vulnerable future versions with breaking changes or security flaws. The devDependencies also use loose constraints that could introduce incompatible or vulnerable versions. Fix: Use strict version pinning or tighter version ranges (e.g., '^0.1.2' or '~0.1.2') and regularly audit dependencies with 'npm audit'. Consider using package-lock.json to lock exact versions in production. - Medium · Native Module Build Process Security —
examples/modules/async-number/package.json, binding.gyp. The package.json includes 'gypfile': true and uses 'node-gyp' for building native C++ modules (binding.gyp present). Native module compilation from source during installation could be exploited if the build environment is compromised or if untrusted code is executed. No build artifact verification or signing is evident. Fix: Provide pre-built binaries for common platforms instead of building from source. If building is necessary, validate the build environment, use sandboxed build processes, and consider code signing. Document the native module dependencies clearly. - Low · Outdated TypeScript Version Constraints —
examples/modules/async-number/package.json. The devDependencies specify '>= 2.2.1' for TypeScript, which is a very old version (released 2017). This version may contain known security vulnerabilities and lacks modern language features. The loose constraint allows outdated versions to be installed. Fix: Update TypeScript to a recent stable version (e.g., '^5.0.0' or newer) and regularly update dependencies. Run 'npm audit' to identify known vulnerabilities in dependencies. - Low · Missing Security Headers and Best Practices Documentation —
Repository root. No evidence of security policy documentation (SECURITY.md), security headers configuration, or vulnerability disclosure policy in the repository structure. The project lacks documented security best practices for users and contributors. Fix: Add a SECURITY.md file documenting how to report vulnerabilities responsibly. Include security guidelines in README and contributing documentation. Consider enabling GitHub security features like dependency scanning and SAST. - Low · Inadequate Input Validation Potential —
examples/modules/async-number/napa/addon.cpp, examples/modules/plus-number/napa/. The codebase includes C++ native modules (addon.cpp, plus-number-wrap.cpp) that interact with JavaScript. Without explicit documentation, there's a risk of improper input validation at the JS-to-native boundary, potentially leading to buffer overflows or crashes. Fix: Implement strict input validation and bounds checking in C++ code. Use safe APIs (std::vector instead of raw buffers). Add input validation tests. Consider using memory-safe alternatives or wrappers.
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.