stockfish.js is Stockfish compiled to WebAssembly, in five sizes
The Stockfish chess engine for web browsers
At a glance
- What is it?
- stockfish.js is Nathan Rugg's WebAssembly build of the Stockfish chess engine, originally written for Chess.com's in-browser analysis board and now maintained as a general purpose project. The engineering is in the packaging: five engine flavours from a 94MB full build to a 1.6MB lite build, and a UCI transport that works over a pipe in Node and over postMessage in the browser.
- Who is it for?
- stockfish.js is worth adopting if you need a strong chess engine in a browser and you have accepted that a 94MB download is not a 94MB download most people will wait for, which is why the lite single threaded build is the sensible default.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 13 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 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Five engines, because one is not a web deliverable
stockfish.js is a WASM implementation by Nathan Rugg of the Stockfish chess engine, written for Chess.com's in-browser engine and maintained as a general purpose project. The current version tracks Stockfish 19.
The interesting decision is that the release ships five engine flavours rather than one, and the table in the readme makes the trade-offs explicit.
The Full engine is about 94MB of JavaScript and WebAssembly, supports threads, and needs cross-origin isolation. The Full single threaded build is the same 94MB without threads and without the isolation requirement. The Lite engine is about 1.6MB, supports threads and needs the isolation headers. The Lite single threaded build is about 1.7MB and needs nothing special. And the ASM-JS engine is about 3MB, is a single file, and is not WebAssembly at all.
The notes explain what each of those costs. The lite engines use a much smaller neural network, so they are far smaller and quite a bit weaker. The ASM-JS engine is compiled to JavaScript rather than WASM, it runs in essentially any browser or runtime that supports JavaScript, and it is very slow and weak, and it is larger than the lite WASM engines, and the recommendation is to use it only as a last resort.
So the shape of the catalogue is a size ladder with a strength ladder running alongside it, and the middle of the ladder, the lite single threaded build, is the one the project itself points most people at.
The audience is developers building a chess product: an analysis board, a puzzle trainer, a bot, a study tool. The second audience is anyone who wants the reference engine running under Node for testing or for a server side game API.
It is a raw UCI engine, not a chess library
The readme is blunt about this. Stockfish.js is a raw engine. It speaks the UCI chess engine protocol over stdin and stdout in Node.js, and over postMessage in the browser, and you need to bring the rest of the parts to make it into a working vehicle.
That means the package is an engine, not a chess library: it accepts uci, position and go commands and prints back info lines and a bestmove. Everything around it, the board, the rules, the notation, the UI, is your code.
The Node usage shows the shape of the API. The engines are published to npm as stockfish, and the package contains all five flavours:
npm install stockfishAnd the package also provides a stockfish command, so you can install it globally and use the engine interactively:
npm install -g stockfish
stockfishFrom a script, you require it as a CommonJS module and the first argument selects which engine to load:
var stockfish = require("stockfish")("lite-single", function onMessage(line) {
console.log("STDOUT:", line);
if (/bestmove \S+/.test(line)) {
console.log("The best move is " + line.match(/bestmove (\S+)/)[1] + ".");
stockfish.terminate();
}
});
stockfish.processCommand("uci");
stockfish.processCommand("go depth 10");The keyword can be full, lite, single, lite-single or asm, or a path to any stockfish.js engine file, and if you leave it out the full engine is used. And you must call terminate() when you are done so the process exits, which is the kind of detail that turns into a hung Node process if you miss it.
If you would rather spawn the engine yourself, findEngine() gives you the path to the engine file so you can pass it to child_process.spawn with your own stdio handling.
In the browser it is a Worker and a postMessage
The browser usage is the same protocol with a different transport, and it is short:
var worker = new Worker("stockfish-19-lite-single.js");
worker.onmessage = function (ev) {
console.log(ev.data);
};
worker.postMessage("uci");
worker.postMessage("position startpos");
worker.postMessage("go depth 10");The engine runs inside a Web Worker, which is the right shape for it, because a search blocks and a blocked main thread means a frozen page. The commands are the same UCI strings, and position startpos sets the starting position before go depth 10 starts a search to depth ten.
Two deployment details are stated plainly. The .js file expects the matching .wasm file to sit next to it, and both files must be served with the correct MIME types, text/javascript and application/wasm. And the lite single-threaded engine works on any static host with no special configuration, which is the deployment story most people want.
The reason the other engines need more is the thread count. The multi-threaded engines need the page to be cross-origin isolated so that SharedArrayBuffer is available, and the server must send both Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp. The readme tells you to check the current page with crossOriginIsolated in the browser console, and notes that the demo server in the examples directory sends those headers automatically.
That is a real cost. Those two headers are not free, they have consequences for what else you can embed on the page, and some static hosts will not let you set them. The single-threaded engines run without them, with the documented limitation that the UCI command setoption name Threads has no effect on them.
The recommendation is the lite engine, and the reason is load time
The section on which engine to use is short and its logic is worth repeating, because it is the opposite of what a chess developer would guess.
The readme says the full engine is objectively stronger, but the lite engine is still far stronger than any human will ever be, and the full engine is so large that it can be very slow to load, which would cause a poor user experience. The conclusion is that most projects should use the lite single-threaded engine because it is fast and does not require any complicated setup.
That is a product argument rather than a chess argument, and it is the right one for a web page. A 94MB download that a user has to wait for before the first analysis appears is a conversion problem, and a user who never sees the engine never sees the stronger evaluation either. A 1.7MB engine that is loaded in a moment and is beyond human strength is the better product, and the people who need the full engine are the ones building a dedicated analysis server where a one time load cost is amortised.
The support matrix is in the same spirit. The WASM engines run on all modern browsers, Chrome, Edge, Firefox, Opera and Safari, on supported systems meaning Windows 10 and later, macOS 11 and later, iOS 16 and later, Linux and Android, as well as currently supported versions of Node.js. Node.js 14 through 18 need the --experimental-wasm-threads and --experimental-wasm-simd flags for the multi-threaded engines. For slightly older browsers there is a Stockfish.js 16 branch, and for chess variants such as three-check and crazyhouse there is a Stockfish.js 11 branch.
Those two older branches are worth knowing about, because a variant of chess or an old browser is exactly the case where the main branch will not help you.
loadEngine is the layer that makes it usable
The examples folder contains a small abstraction layer, examples/loadEngine.js, and the readme describes exactly what it does, which is more than a convenience wrapper.
It works in both Node.js and the browser. It queues commands, matches output back to the command that produced it, streams info lines, reports engine download progress, and works with any UCI compatible engine, including native binaries.
Each of those is a real problem you would otherwise solve yourself. Command and output pairing is the interesting one, because UCI is a conversational protocol where the engine answers asynchronously and the lines coming back do not carry the identifier of the request that caused them. A wrapper that pairs them lets your code say 'go depth 10' and then receive the info lines and the bestmove that belong to that search, which is the difference between a usable integration and a race condition.
The download progress reporting matters for the same reason the engine size matters. A 94MB engine on a slow connection is a spinner, and a spinner with no percentage is a support ticket. And the ability to work with any UCI engine, including a native binary, means the same code can be tested against the real Stockfish during development and shipped with the WASM build.
The examples folder shows the range: demo.html, server.js, get-engine.js, enginegame.js, and a set of Node examples named node_abstraction, node_direct, node_module and node_spawn, which between them cover the four different ways of talking to the engine, from the abstraction layer down to spawning the process yourself.
Compiling the engine needs a pinned emscripten
You only need to compile the engine if you want to make changes to the engine itself, and the requirement is a specific toolchain.
The build needs emscripten 6.0.9 installed and in your path, and build.js checks your version and warns if it does not match. There is a --skip-em-check flag to bypass the check, and a --strict-em-check option to turn a mismatch into an error instead of a warning.
That last detail is a good sign. A build script that pins a nightly compiler version and then refuses to be quiet about a mismatch is a project that has been bitten by a compiler upgrade changing the output, and the package scripts reflect the same discipline. There are four build targets, one per flavour, using node build.js with flags, and the build is forced with -f in each of them.
The repository layout shows a C++ project with the Emscripten specific build script at the root, the sources in src, the Node side in index.js and scripts, where scripts/cli.js is the binary the package exposes and scripts/findEngine.js is the module that resolves an engine path, and a tester.js plus a tests directory. There is a .clang-format file, which tells you the C++ is formatted with a specific tool rather than by hand.
The packaging is also handled explicitly, with prepack and postpack scripts that run before and after npm publish, and the files list in the package metadata ships only the bin directory, index.js, the two scripts, the readme and Copying.txt, which is the licence text of the underlying engine.
GPL-3.0 is the licence that decides where you can put it
The licence is GPL-3.0, and the repository carries Copying.txt at the root, which is the licence text of the underlying engine rather than a file the project wrote itself. That is the correct thing to ship, and it is a reminder that what you are distributing is Stockfish.
For a website, GPL has a specific meaning: if you distribute the engine to users, you have to offer them the corresponding source. In practice that means your build pipeline has to publish the engine source alongside the site, or link to it in a way that satisfies the licence, and a team that has never thought about copyleft will hit this at the worst possible moment, which is after the site is built.
The package metadata lists the licence as GPL-3.0 and the author as Nathan Rugg, with Chess.com listed as a contributor, which is the shape of a project with a real commercial user behind it and therefore a real interest in keeping the licence terms clean.
On the maintenance side, the repository is not archived, the last push was on 2026-10-10, and the release history shows v18.0.0 on 2026-02-11, v19.0.0 on 2026-09-15 and v19.0.1 on 2026-10-10. So the engine is tracked in step with upstream Stockfish, which is the thing that matters here, because a chess engine that is a year behind the reference is a chess engine that is measurably weaker, and the value of this project is that it is not.
The package version tracks the engine version exactly, 19.0.1, with a separate buildVersion of 19, and there are no runtime dependencies at all, with terser as the only development dependency for the minification of the JavaScript glue.
Editorial conclusion
stockfish.js is worth adopting if you need a strong chess engine in a browser and you have accepted that a 94MB download is not a 94MB download most people will wait for, which is why the lite single threaded build is the sensible default. It is the wrong choice if you need the full engine's strength in a page, since the documentation is explicit that the lite engine is quite a bit weaker, and it is the wrong choice if your site cannot send cross-origin isolation headers and you want threads. Before you ship it, decide which flavour you are loading and check that your host serves the .wasm with the application/wasm MIME type, and note that the current version is 19.0.1 from 2026-10-10 with the repository pushed to on the same day.
Frequently asked questions
How do I install stockfish.js in Node.js?
Run npm install stockfish, which brings in all five engine flavours, and require it as a CommonJS module. The package also provides a stockfish command, so npm install -g stockfish gives you an interactive engine, and findEngine() returns the path to an engine file if you want to spawn the process yourself.
Which Stockfish.js engine should I use in a web page?
The documentation recommends the lite single-threaded engine for most projects, because the full engine is about 94MB and can be very slow to load, while the lite engine is far stronger than any human and needs no special server configuration. The lite engines use a much smaller neural network and are quite a bit weaker, and the ASM-JS engine is a last resort.
Why do the multi-threaded stockfish.js engines need special headers?
They need the page to be cross-origin isolated so that SharedArrayBuffer is available, which means the server must send both Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp. The single-threaded engines run without those headers, but the UCI command setoption name Threads has no effect on them.
How does stockfish.js talk to the engine in the browser?
It is a raw engine, so you run it in a Web Worker and send UCI commands with postMessage, for example worker.postMessage("go depth 10"). The .js file expects the matching .wasm file beside it, both served with the correct MIME types, text/javascript and application/wasm.
Do I need to compile the engine to use stockfish.js?
No. Prebuilt engines are published to npm as the stockfish package and to the releases page, and the readme says you only need to compile if you want to change the engine itself. Compiling requires emscripten 6.0.9 in your path, with build.js checking the version and offering --skip-em-check and --strict-em-check.
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/nmrugg-stockfish-js)Was this useful?