jco turns WebAssembly components into JavaScript modules and CLI tools
JavaScript toolchain for working with WebAssembly Components
At a glance
- What is it?
- jco is the Bytecode Alliance's JavaScript toolchain for the WebAssembly Component Model, scaffolding projects, transpiling components to ES modules, running them and shipping WASI shims. It suits Node and browser teams consuming component-model tooling, and it sits on a fast-moving preview standards line.
- Who is it for?
- Adopt jco if you are building or consuming WebAssembly components from JavaScript and TypeScript, and you want one CLI that scaffolds, builds, transpiles and runs components instead of stitching together wasm-tools, bindgen and a WASI shim by hand. Do not adopt it if you need stable, pinned component-model semantics, because the release names carry preview2 and preview3 shim versions and the WASI worlds bundled by default to 0.3.
- Can I use it commercially?
- Yes. Apache-2.0 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 received new commits within the last day.
- What is it written in?
- Mainly TypeScript, 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
jco is a multi-tool, not a single transpiler
jco provides a JavaScript-native toolchain for working with WebAssembly Components, and the README states the goal plainly: jco aims to be a convenient multi-tool for the JS WebAssembly ecosystem.
The list of things it does is what defines the project. You can scaffold a new JavaScript or TypeScript component project from a WIT world with jco scaffold, build WebAssembly components from JavaScript or TypeScript with componentize-js or componentize-qjs, transpile WebAssembly components into ES modules that run in environments like NodeJS and the browser, run WebAssembly components whether single-shot applications or web servers, reuse the component workflows from your own JS projects, and use wasm-tools as a library from JavaScript.
The run capability is the one that differentiates it from a build tool. The README compares it to wasmtime run and wasmtime serve, which is a useful reference point: jco is putting a runtime in reach of JavaScript developers who would otherwise have to leave the JS ecosystem to execute a component.
The transpile step is described as combining platform-native WebAssembly core support with the advanced features of WebAssembly Components. In practice that means the component's WIT-level interface is lowered to ordinary JavaScript imports and exports, so the result is an ES module rather than a raw component requiring a component-model runtime. That is the whole trick behind the toolchain, and it is why the WASI shims exist.
Nine packages and four Rust crates live in one repository
Because jco does many things, the README says it contains many subprojects organised in the repository, and the table spells out the layout.
On the JavaScript side there are packages/jco for the CLI, packages/jco-transpile for the transpilation functionality, packages/jco-std, described as a standard library providing integrations for popular JS frameworks and paradigms, and packages/jco-node-fs, which is Rust and JS and provides native Node.js filesystem helpers used by Jco's WASI shims. Two shim packages sit alongside: packages/preview2-shim, which provides a mapping of WASI Preview 2 for NodeJS and browsers, and packages/preview3-shim, which does the same for WASI Preview 3 in NodeJS. There is also packages/rolldown-plugin-jco, a Rolldown and Rollup plugin for importing WebAssembly Components through Jco.
The Rust side has four crates. js-component-bindgen enables jco transpile and other features by reusing the Rust WebAssembly ecosystem, js-component-bindgen-component is a WebAssembly component that, when transpiled, makes js-component-bindgen available in JavaScript, and wasm-tools-component is a WebAssembly component containing pieces of wasm-tools used by jco. The fourth, xtask, is the build orchestrator.
The root package.json shows how the build is driven: cargo xtask build debug for a normal build, cargo xtask build release for a release build, and separate generate tasks for the preview2 and preview3 WASI types. The Cargo workspace confirms the shape, with js-component-bindgen, js-component-bindgen-component, wasm-tools-component, xtask and jco-tests as default members, and packages/jco-node-fs as an additional member.
Scaffolding a component from a builtin WASI world takes one command
Installing the CLI is a single pnpm command:
pnpm install @bytecodealliance/jcoJco can then be used either as a library import or as a CLI through the jco command.
The first real task is scaffolding. The README shows creating a TypeScript component project from Jco's built-in WASI CLI world:
pnpm exec jco scaffold my-command --wit builtin:wasi-command
# Note that you can also scaffold from an existing WIT package
# directory instead:
# jco scaffold my-component --wit path/to/witThe scaffolding creates a folder named after the first argument, and you switch into it and build:
cd my-command
pnpm install
pnpm check
pnpm test
pnpm buildJco bundles three common starting points, and the README says they default to WASI 0.3. The builtin:wasi-command entry uses the wasi:cli/command world from the upstream WASI CLI WIT interfaces, builtin:wasi-reactor uses the wasi:cli/imports world from the same place, and builtin:wasi-proxy uses the wasi:http/service world from the upstream WASI HTTP WIT interfaces.
The version suffix matters if you are not ready for 0.3. Adding the @0.2.x suffix uses the bundled WASI 0.2 interfaces instead, for example builtin:[email protected]. You can also pass a WIT file or package directory to --wit for a custom world.
The generated project is not a bare skeleton. The README says it includes guest component TypeScript declarations, implementation skeleton code, Node.js and web type-check and build scripts, configuration files and a README. Examples of common patterns live in the examples/components folder, and the Jco Book covers language, world, target and package-manager options.
The preview2 and preview3 shims are the version boundary that defines the tool
The release names are the clearest statement of where this project stands. The recent tags are preview3-shim-v0.11.0 on 2026-10-15, preview2-shim-v0.30.0 on 2026-10-15 and jco-std-v0.9.0 on 2026-10-15, all published within hours of each other.
That naming is not cosmetic. jco exists to bridge a moving standards boundary, and the two shim packages represent the two sides of it. The preview2-shim provides a mapping of WASI Preview 2 for NodeJS and browsers, and the preview3-shim provides a mapping of WASI Preview 3 for NodeJS. The bundled worlds default to WASI 0.3, with the @0.2.x suffix available for the older interfaces.
The consequence for an adopter is concrete. When you scaffold a component, the world you pick determines which WASI semantics your guest code compiles against, and the shim that ships with your chosen jco version determines how the host environment implements them. A component built against one preview line is not trivially portable to the other, and the README does not describe a compatibility bridge between them.
The justfile shows how both are exercised in the test suite. The test-preview2 recipe runs the pnpm build, generates preview2 tests through cargo xtask, and then runs cargo test twice, once for node_ prefixed tests and once for deno_ prefixed tests. Two runtimes, two test filters, one recipe.
The repository is not archived and the last push was on 2026-10-19, so the project is moving at the pace of the spec it tracks.
Rust and JavaScript meet in js-component-bindgen
The build output of a jco project is not produced by JavaScript alone. The Rust crate js-component-bindgen is the piece that does the real work, and the README describes its role as enabling jco transpile and other features by reusing the Rust WebAssembly ecosystem.
The trick with js-component-bindgen-component is worth understanding. It is a WebAssembly component that, when transpiled, makes js-component-bindgen itself available in JavaScript. So the bindgen code, which is Rust, reaches the JavaScript world by being turned into a component and then transpiled through the same machinery as everything else. The same pattern applies to wasm-tools-component, a WebAssembly component containing pieces of wasm-tools used by jco, which is how the README can list using wasm-tools as a library from JavaScript as a capability of jco.
The Cargo workspace dependencies show the ecosystem jco is standing on. wasmtime-environ at 49.0.0 with the component-model, compile and anyhow features, wasm-encoder and wasmparser at 0.259.0, wasmprinter, and webidl2wit, which is the bridge for Web IDL descriptions. tokio, serde, serde_json, anyhow and structopt handle the async runtime, serialisation and CLI parsing, and xshell handles shell scripting inside the xtask orchestrator.
The release profile is tuned for size. opt-level is 'z', lto is true, codegen-units is 1, strip is true, debug assertions are off and panic is 'abort'. That is a reasonable set of choices for a binary whose compiled output is distributed to JavaScript developers, though it also means compile times are on the slower side.
The workspace version is 1.10.0 with edition 2024, and the repository ships a rust-toolchain.toml, so the Rust side is pinned by the repository rather than by the user.
Rolldown and Rollup plugins cover the bundler side of component imports
Transpiling a component to an ES module is only half the job if your application is bundled. The packages/rolldown-plugin-jco package exists for exactly that case: it is a Rolldown and Rollup plugin for importing WebAssembly Components through Jco.
This matters because the two bundlers are not interchangeable historically, and the plugin supports both. A project that has already standardised on one of them can keep it and still import components the same way it imports JavaScript modules, rather than adding a separate build step and a separate output path.
The jco-std package sits in the same category. The README describes it as a standard library for Jco which provides integrations for popular JS frameworks and paradigms. The word integrations is doing real work there. A component that wants to talk to the host application, receive structured data, and hand results back needs a convention for the boundary, and a standard library of adapters is how the project avoids every project inventing its own.
The scripts at the root show the testing breadth. There is a task for installing Puppeteer, and a second one for installing firefox through the same script, which tells you the browser is part of the test matrix rather than an afterthought. The build:test:idl task runs scripts/create-idl-component.mjs, and the Web IDL bridge in the Rust dependency list is the reason a Web IDL component can exist as a fixture at all.
For a team already using Jco inside a bundler-based build, the plugins are what turn the toolchain from a set of scripts into something that fits the existing pipeline.
Apache-2.0, a governance-boundary repository, and a fast release cadence
jco is a Bytecode Alliance project, and the licence is Apache-2.0 with the LICENSE file at the repository root as the authoritative text. That is a permissive licence with no copyleft obligations for the JavaScript or Rust code that builds on it, and this is a licensing statement rather than legal advice.
The repository structure reflects that jco sits on a boundary between two projects. The top level has a Cargo.toml and Cargo.lock alongside package.json and pnpm-lock.yaml, a pnpm-workspace.yaml for the JavaScript side, a justfile for task running, and a .gitmodules file plus a submodules/ directory, which is how the Rust side pulls in the wasm-tools sources it embeds. There is a CODEOWNERS file and both a CODE_OF_CONDUCT.md and an ORG_CODE_OF_CONDUCT.md, the latter inherited from the parent organisation.
The tooling choices are worth a note. Formatting and linting are handled by oxfmt and oxlint rather than Prettier and ESLint, configured through .oxfmtrc.json and .oxlintrc.json, and commit messages go through commitlint with a conventional-commits config. The justfile allows the tool binaries to be overridden through the JUST, JUST_DIR, CARGO and PNPM environment variables, which is the usual arrangement for a repository that has to build the same code in CI and in a contributor's shell.
The release pattern is the part to plan around. Three tagged releases on 2026-10-15, each for a different subproject, means jco ships per-package versions rather than one version for the tool as a whole. If you depend on the CLI, the transpiler and a shim at the same time, you are managing three version streams.
Editorial conclusion
Adopt jco if you are building or consuming WebAssembly components from JavaScript and TypeScript, and you want one CLI that scaffolds, builds, transpiles and runs components instead of stitching together wasm-tools, bindgen and a WASI shim by hand. Do not adopt it if you need stable, pinned component-model semantics, because the release names carry preview2 and preview3 shim versions and the WASI worlds bundled by default to 0.3. Before you start, confirm your pnpm and Rust toolchains are present, decide which builtin world you are targeting, and check whether the component you need exposes a WIT world that jco scaffold can start from.
Frequently asked questions
How do I install the jco CLI?
The README shows a single command, pnpm install @bytecodealliance/jco, and then says Jco can be used either as a library import or as a CLI through the jco command.
How do I create a new WebAssembly component project with jco?
Run pnpm exec jco scaffold my-command --wit builtin:wasi-command to create a folder from a bundled WIT world, then cd into it and run pnpm install, pnpm check, pnpm test and pnpm build. You can also point --wit at a path/to/wit package directory for a custom world.
What is the difference between builtin:wasi-command, builtin:wasi-reactor and builtin:wasi-proxy?
The README says jco bundles three common starting points that default to WASI 0.3. builtin:wasi-command uses the wasi:cli/command world, builtin:wasi-reactor uses the wasi:cli/imports world, and builtin:wasi-proxy uses the wasi:http/service world from the upstream WASI HTTP WIT interfaces.
What do the preview2 and preview3 shim packages do?
The preview2-shim package provides a mapping of WASI Preview 2 for NodeJS and browsers, and the preview3-shim provides a mapping of WASI Preview 3 for NodeJS. The recent jco releases are published per subproject, for example preview2-shim-v0.30.0 and preview3-shim-v0.11.0, so the shim versions can differ.
Can I import WebAssembly Components directly in my bundler with jco?
Yes. The repository ships packages/rolldown-plugin-jco, a Rolldown and Rollup plugin for importing WebAssembly Components through Jco, so components can be imported the same way as other modules in a bundled build.
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/bytecodealliance-jco)Was this useful?