RepoPilotOpen in app →

microsoft/napajs

Napa.js: a multi-threaded JavaScript runtime

Mixed

Stale — last commit 4y ago

worst of 4 axes
Use as dependencyConcerns

non-standard license (Other); last commit was 4y ago

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 34+ active contributors
  • Other licensed
  • CI configured
Show 4 more →
  • 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 ConcernsMixed 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.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/microsoft/napajs?axis=fork)](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:

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

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>microsoft/napajs</code></summary>
#!/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).

</details>

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 capabilities
  • CMakeLists.txt — Root build configuration for the C++ native runtime; required to understand compilation dependencies and module structure
  • docs/architecture.png — Visual architecture diagram showing Napa's multi-threaded design; critical reference for understanding component relationships
  • docs/api/zone.md — API documentation for zones (thread pools); zones are the fundamental execution unit in Napa.js
  • docs/design/transport-js-builtins.md — Design document explaining inter-thread communication and data transport mechanisms; core to understanding Napa's concurrency model
  • benchmark/bench.ts — Benchmark suite demonstrating performance characteristics and typical usage patterns
  • build.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 ApplicationZone API — Developer calls zone.execute() with function code and arguments
  • Zone APIData Transport — Arguments serialized to JSON/binary representation
  • Data TransportWorker Thread Queue — Serialized work item enqueued for next available worker
  • Worker Thread QueueV8 Isolate — Function code and deserialized arguments provided to isolated JavaScript context
  • undefinedundefined — undefined

🛠️How to make changes

Create a new Napa example module

  1. Create module directory structure: examples/modules/your-module/ with lib/, napa/, test/ subdirectories and package.json (examples/modules/plus-number/package.json)
  2. Write TypeScript API wrapper in lib/your-module.ts exposing the module interface (examples/modules/plus-number/lib/plus-number.ts)
  3. Create C++ native addon in napa/addon.cpp using V8 bindings to wrap native functions (examples/modules/plus-number/napa/addon.cpp)
  4. Configure compilation with binding.gyp (for node-gyp) or CMakeLists.txt for cmake builds (examples/modules/plus-number/binding.gyp)
  5. Add TypeScript tests in test/test.ts and verify with npm test (examples/modules/plus-number/test/test.ts)

Add a performance benchmark

  1. Create new benchmark file in benchmark/ directory following naming pattern: benchmark/your-benchmark.ts (benchmark/execute-overhead.ts)
  2. Import bench utilities and define benchmark configurations with min/max worker counts (benchmark/bench-utils.ts)
  3. Register benchmark in main benchmark runner by adding to benchmark/bench.ts imports and execution (benchmark/bench.ts)

Extend Napa runtime capabilities

  1. Add new API documentation under docs/api/ describing the new capability (docs/api/zone.md)
  2. Create design rationale document in docs/design/ if the feature involves significant architectural changes (docs/design/transport-js-builtins.md)
  3. 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
  • nodejs/node — Node.js worker_threads module provides similar multi-threaded JavaScript; understanding Node's approach clarifies Napa.js's design decisions
  • v8/v8 — Napa.js is built directly on V8; critical for understanding isolate lifecycle, GC behavior, and native binding patterns
  • parro-nodo/parro — Alternative JavaScript parallelism framework; useful for comparing zone-based vs. actor-model approaches
  • Microsoft/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

📝Recent commits

Click to expand
  • 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.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · microsoft/napajs — RepoPilot