txiki.js: QuickJS plus libuv with web platform APIs bolted on
A tiny JavaScript runtime
At a glance
- What is it?
- A small C JavaScript runtime that pairs QuickJS-ng with libuv, exposes fetch, WebSocket and sockets, and can compile a script into a standalone executable. Aimed at people who want a runtime they can reason about.
- Who is it for?
- txiki.js is worth looking at when the deciding factor is that you can read the whole thing, or when you need a runtime with real POSIX reach, since `tjs:ffi`, `tjs:sqlite`, TCP, UDP and Unix sockets go well beyond what a browser-targeted engine gives you.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 8 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 9, 2026, and from our analysis. They are not legal advice.
Editorial analysis
QuickJS-ng for the engine, libuv for the platform
The architecture is stated in one line and it explains nearly everything about the project. txiki.js uses QuickJS-ng as its JavaScript engine and libuv as the platform layer, and the README's phrase is that it is built on the shoulders of giants. QuickJS-ng is the successor to Bellard's QuickJS, and libuv is the same event loop that Node.js runs on.
The name is Basque: the README glosses *txikia* as small, tiny, and the repository description is simply "A tiny JavaScript runtime". The implementation language is C, and the repository topics confirm the stack with `javascript`, `libuv`, `quickjs` and `wasm`.
The other defining constraint is a standards target rather than a feature list. The project aims to be WinterTC compliant, which is a web-interoperability specification for server-side JavaScript runtimes. That framing is the honest way to place the project: it is competing on doing the web platform correctly, not on doing everything Node does.
Three commands from clone to REPL
The README's quick start is three commands, and the flags in the clone line matter more than they look.
git clone --recursive https://github.com/saghul/txiki.js --shallow-submodules && cd txiki.js`--recursive` is required because `.gitmodules` is present in the tree: QuickJS-ng and libuv are submodules, and without the flag the build fails at a point where the error will not explain itself. `--shallow-submodules` keeps the checkout small.
makeThat runs CMake. The Makefile starts with `BUILDTYPE?=Release`, `MIMALLOC?=ON` and a jobs default that reads the processor count, falling back through `sysctl -n hw.ncpu` on macOS, `nproc` elsewhere, and finally 4. The CMake configure line is `cmake -B build -DCMAKE_BUILD_TYPE=$(BUILDTYPE) -DBUILD_WITH_MIMALLOC=$(MIMALLOC)`, so memory allocation goes through mimalloc unless you turn it off.
./build/tjsDetailed instructions, including Windows, live at txikijs.org under Building.
What the standard library reaches beyond a browser
The features list splits into three groups, and the third group is what separates this from an embedded engine.
Web platform APIs come first: `fetch`, `WebSocket`, `Console`, `setTimeout`, `Crypto`, Web Workers. Then the platform group: TCP, UDP and Unix sockets, an HTTP server with WebSocket support, file I/O, child processes and signal handling.
The standard library is where the project gets opinionated. Modules include `tjs:sqlite`, `tjs:ffi`, `tjs:path` and `tjs:hashing`. SQLite in the runtime means a script can open a local database without a dependency. FFI means a script can call into a shared library directly, which is the feature that makes txiki.js interesting for command-line tools that need to reach something Node would require a native addon for.
The last feature is the one with the most leverage: standalone executables via `tjs compile`. That takes a script and its JavaScript bundle, runs them through the `tjsc` compiler target in the Makefile, and embeds the result so the output runs on a machine with no runtime installed. The Makefile's `TJSC_PARAMS_STIP=-s` and the `--minify --keep-names` esbuild parameters show what gets baked in.
Release notes read like a systems changelog
The most recent release is v26.6.0, published on 2026-06-22, and the last push was on 2026-09-14, so the project is active and behind a roughly monthly tag. The versioning scheme itself is worth noting: `v26.6.0` is not a semantic version tracking a library API. It tracks a year and month, which is the convention of a runtime rather than a package.
What is in that release is mostly not user-facing. There is a build fix so release zip files keep the executable bit, a Windows change to suppress GUI error dialogs in CLI mode, macOS plugin build fixes, and a CI fix for the Windows MSVC 2025 path. Two entries describe real engineering: the team implemented its own event loop integration for the WebSocket library rather than using lws directly, and added zero-copy pointer views to the FFI module.
Release v26.5.0 shows the maintenance texture more clearly, and it is worth reading as a list of the sharp edges this runtime has. There is a fix for a use-after-free in the file watcher when `uv_fs_event_start` fails, a fix preventing the garbage collector from collecting active FileWatcher objects, a fix for SQLite close with live statements, a signal handle leak on `uv_signal_start` failure, and internal VM bindings hidden behind gated `tjs:internal/` modules. Those are not glamorous entries, and they are a fair signal of what running a custom runtime involves.
The build system reflects the same posture: one entry in v26.6.0 enables `-Werror` for the `tjs` target and fixes all resulting warnings.
The Dockerfile is the fastest way to see it work
A container recipe ships in the repository, and it is small enough to read in one pass. It builds on Alpine, installs the toolchain, compiles with `make distclean && make`, then copies only three things into the runtime stage: the `tjs` binary, the `examples/` directory, and an entry script.
RUN apk add build-base cmake libffi-dev git --update-cache
RUN chmod 755 /usr/local/bin/docker-entrypoint.shThe runtime stage needs only `libstdc++`, `libffi` and `tini`, and the default command runs `/examples/hello_world.js`. That `hello_world.js` path is the fastest way to confirm the runtime works on an unfamiliar platform.
Note what the container is not for. It runs a script and exits, which makes it a convenient way to execute JavaScript in isolation, not a way to run a long-lived service image.
One naming trap is worth flagging: the repository's `package.json` is version `0.0.0` and describes itself as utilities for txiki.js, marked private. It exists to build the documentation website and run ESLint, and its dependencies are tooling like `esbuild` and `typedoc`, not runtime packages. Do not read that file as a manifest for the runtime itself.
Where to read further and what the README does not tell you
The README is deliberately short, roughly a screen of feature list plus a link. Everything substantive is at txikijs.org, and the `website/` directory in the repository is the source of that documentation, with typedoc in the dev dependencies for the API reference and an `examples/` directory shipped into the container.
The repository also carries files that suggest how the project is worked on: a `CLAUDE.md`, an `eslint.config.mjs`, a `.clang-format`, a `ubsan.supp` file for undefined behaviour sanitizer suppressions, and a `benchmark/` directory. The sanitizer suppression file is a reasonable signal about the project's attitude to memory safety, which matters given that `tjs:ffi` hands raw pointers to JavaScript.
Supported platforms are GNU/Linux, macOS, Windows and other Unixes, with the README asking people to test the last category. That phrasing is a genuine warning: on an unlisted Unix you should expect to be the person who finds the problem.
What is absent is as informative as what is present. The README says nothing about TypeScript, nothing about npm package resolution, nothing about module loading beyond the standard library, and nothing about debugging tooling. For a runtime aimed at the web platform subset, that absence may be a deliberate boundary rather than a gap, but it does mean you should check the compatibility list on the documentation site before committing to it.
Editorial conclusion
txiki.js is worth looking at when the deciding factor is that you can read the whole thing, or when you need a runtime with real POSIX reach, since `tjs:ffi`, `tjs:sqlite`, TCP, UDP and Unix sockets go well beyond what a browser-targeted engine gives you. It is the wrong choice for a large dependency-heavy project, since a QuickJS-based runtime has a much smaller ecosystem surface than Node, and the README says nothing about TypeScript, tooling or npm compatibility guarantees. The repository contains a `CLAUDE.md` file and a `website/` directory holding the documentation, which is where the real answers live. Start with the three-line build in the README, run `./build/tjs` for the REPL, and read `tjs compile` before deciding whether it fits a deployment.
Frequently asked questions
What is txiki.js and what is it built on?
It is a small JavaScript runtime written in C that uses QuickJS-ng as its JavaScript engine and libuv as its platform layer. It aims to be WinterTC compliant and ships web platform APIs such as `fetch` and `WebSocket` alongside TCP, UDP and Unix sockets, file I/O and child processes.
How do I build txiki.js from source?
Clone with `git clone --recursive https://github.com/saghul/txiki.js --shallow-submodules` so the submodules for QuickJS-ng and libuv come along, run `make` to build with CMake, then run `./build/tjs` to start the REPL. Detailed instructions including Windows support are on txikijs.org.
Can txiki.js produce a standalone executable?
Yes, through the `tjs compile` feature, which produces standalone executables from a script by bundling its JavaScript and embedding it. The build system that supports this lives in the `tjsc` compiler target in the Makefile.
Which platforms does txiki.js support?
GNU/Linux, macOS, Windows and other Unixes, though the README asks people to test the last group, so expect to be the one finding issues on an unlisted Unix. The repository also ships a Dockerfile built on Alpine that compiles the binary and runs `examples/hello_world.js` by default.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/saghul-txiki-js)