Python wrapper around quickjs-ng, the actively maintained fork of the QuickJS JavaScript engine.
Drop-in replacement for the archived quickjs package — import quickjs works unchanged.
pip install quickjs-ngRequires Python ≥ 3.10. Pre-built wheels are available for Linux (x86_64, i686, aarch64), Windows (AMD64, x86), and macOS (arm64), for CPython 3.10+ and PyPy 3.10/3.11.
import quickjs
# Evaluate expressions
ctx = quickjs.Context()
ctx.eval("1 + 2") # => 3
# Call JS functions from Python
ctx.eval("function add(a, b) { return a + b; }")
add = ctx.get("add")
add(3, 4) # => 7
# Call Python functions from JS
ctx.add_callable("py_add", lambda a, b: a + b)
ctx.eval("py_add(3, 4)") # => 7
# Use the Function helper for thread-safe execution
f = quickjs.Function("f", "function f(x) { return x * 2; }")
f(21) # => 42
# Resource limits
ctx.set_memory_limit(1024 * 1024) # 1 MB
ctx.set_time_limit(5) # 5 seconds of CPU time
ctx.set_max_stack_size(512 * 1024) # 512 KB stackEach Context owns an isolated QuickJS runtime — there is no shared state between contexts. A single Context is not thread-safe and must not be used from multiple threads.
Recommended patterns:
-
Context per thread — create a separate
Contextin each thread. No locking, no overhead, full parallelism:import threading, quickjs def worker(): ctx = quickjs.Context() print(ctx.eval("1 + 1")) threads = [threading.Thread(target=worker) for _ in range(4)] for t in threads: t.start()
-
Functionhelper — wraps aContextwith a dedicated worker thread and lock, safe to call from any thread:f = quickjs.Function("f", "function f(x) { return x * 2; }") # safe to call f(21) from any thread
| Pattern | Thread-safe | Overhead |
|---|---|---|
| Context per thread | ✅ | None |
Function helper |
✅ | Small (executor dispatch) |
Shared Context |
❌ | — |
Free-threaded Python (3.13t / 3.14t): Both patterns remain safe. The GIL was never relied upon for thread-safety.
musl / Alpine: Worker threads are automatically created with an 8 MB stack (matching glibc defaults) so set_max_stack_size and deep recursion work correctly on musl-based systems.
Version format is X.Y.Z.P where X.Y.Z matches the upstream quickjs-ng tag and P is the wrapper patch (starts at 1 per upstream release). Wheels are built automatically when a new upstream tag is detected.
Requires a C compiler and uv.
git clone --recurse-submodules https://github.com/genotrance/quickjs-ng.git
cd quickjs-ng
make install
make test| Target | Description |
|---|---|
make install |
Create venv, build C extension, install pre-commit |
make test |
Run tests with coverage |
make check |
Run linters and type checking |
make build |
Build sdist and wheel |
make clean |
Remove build artifacts |
make publish |
Publish to PyPI |
Bug reports and pull requests are welcome at https://github.com/genotrance/quickjs-ng/issues.
- Fork and clone with
--recurse-submodules. - Run
make installto set up the venv, build the C extension, and install pre-commit hooks. - Create a feature branch, make changes, add tests in
tests/. - Run
make check && make test— all checks must pass. - Open a pull request. CI runs on Ubuntu, Windows, and macOS across Python 3.10–3.14 (including free-threaded 3.13t/3.14t) and PyPy 3.10/3.11.
Full technical documentation is in the docs/ folder:
| File | Contents |
|---|---|
| docs/porting.md | Porting history from PetterS/quickjs |
| docs/c-extension.md | C extension design and stable ABI migration |
| docs/build.md | Build system: setup.py, pyproject.toml, wheels |
| docs/ci.md | GitHub Actions workflows |
| docs/threading.md | Threading model and musl stack fix |
| docs/testing.md | Test suite layout and memory leak tests |
| docs/versioning.md | Version scheme and automated stamping |
| docs/typing.md | Type annotations and mypy configuration |
This project is a fork of quickjs by Petter Strandmark. The original design of the C bindings, the Function thread-safety wrapper, and the overall API shape are all his work.
The porting to quickjs-ng, the stable ABI migration, the expanded test suite, CICD and all documentation were developed with the assistance of LLMs.
MIT