A dev container. In your tab.
See the code
Node.js, npm and your dev server, in the browser. No Docker, no cloud VM. Open source, MIT, self-hosted.
[!WARNING] Mimic is experimental. It has been developed largely with AI assistance, and it is not recommended for production use until its first major version (1.0). While it is 0.x, the API may change between minor versions.
Mimic is a browser-based runtime that executes Node.js applications and shell commands entirely inside a browser tab. Programs run in Web Workers over an in-memory file system, npm, pnpm and Yarn install real packages from the npm registry, and a server a program starts becomes a URL your page can load in an iframe. Workloads that used to need a cloud VM per user, such as installing packages, running a dev server or executing user code, run client-side instead, on the user's CPU, with nothing to provision and nothing leaving the browser but package downloads and the project's own requests. Mimic is open source under the MIT licence and served from your own origin: no vendor service, no API key, no usage limits.
Three ways to run a user's Node.js project from a web app:
| Cloud VM or container | WebContainers | Mimic | |
|---|---|---|---|
| Licence | A hosted service's terms, or infrastructure you run | The vendor's licence and terms | MIT: self-hosted, no API key, no usage limits |
| Where the project runs | A remote machine per user | The user's tab; the runtime served by the vendor | The user's tab; the runtime served from your origin |
| Startup | Provision or wake a machine | No machine; installs use the user's CPU | No machine; installs use the user's CPU |
| Server cost per user | A machine per active user | None beyond hosting the page | None beyond hosting the page |
| Isolation | A VM or container | The browser's sandbox | A cross-origin-isolated tab, optionally a separate preview origin |
| Limits | Anything Linux runs, Docker included | No native binaries or Docker; a tab's memory | No native binaries or Docker; a tab's memory |
sh -c and the shell scripts package scripts use, with common commands such as
ls, cp and sed.npm install @mimic-js/runtime
import { Mimic } from '@mimic-js/runtime';
const container = await Mimic.boot();
await container.fs.mount({
'server.mjs': {
file: {
contents: `
import http from 'node:http';
http.createServer((request, response) => response.end('hello')).listen(3000);
`
}
}
});
container.endpoints.on('published', (endpoint) => {
document.querySelector('iframe').src = endpoint.url;
});
const server = await container.spawn('node', ['server.mjs']);
server.stdout.pipeTo(new WritableStream({ write: (chunk) => console.log(new TextDecoder().decode(chunk)) }));
// Later: server.kill(); await container.teardown();
One container runs per page at a time.
The page that calls boot() must be cross-origin isolated, so serve it (and the
package's dist/assets) with these headers:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp (or credentialless)
boot() rejects with an error naming them when they are missing. With Vite, the
plugin sends them from vite dev and vite preview:
import { mimic } from '@mimic-js/runtime/vite';
export default defineConfig({ plugins: [mimic()] });
The package README covers the rest: webpack, use without a bundler, production hosting, and the preview origin.
Requires Node 22 and pnpm 11.
pnpm install
pnpm run dev # start the site and its playground at http://localhost:5173
pnpm run test:build # build and typecheck every project
pnpm run test:unit # Vitest unit tests of the runtime
pnpm run test:e2e # Playwright browser tests, including every Compatibility Claim
pnpm run package:check # build the package and check what it would publish
docs/README.md maps the rest of the documentation, including the
architecture decisions under docs/adr/.
Mimic needs a cross-origin-isolated page (for SharedArrayBuffer), Web Workers
and Service Workers. The Compatibility Claims run in Chromium. Chromium and
Firefox support both embedder policies; Safari needs require-corp, as it does
not support credentialless. The package README explains
what each embedder policy changes for the rest of your page.
A dev container. In your tab.
See the code
Node.js, npm and your dev server, in the browser. No Docker, no cloud VM. Open source, MIT, self-hosted.
[!WARNING] Mimic is experimental. It has been developed largely with AI assistance, and it is not recommended for production use until its first major version (1.0). While it is 0.x, the API may change between minor versions.
Mimic is a browser-based runtime that executes Node.js applications and shell commands entirely inside a browser tab. Programs run in Web Workers over an in-memory file system, npm, pnpm and Yarn install real packages from the npm registry, and a server a program starts becomes a URL your page can load in an iframe. Workloads that used to need a cloud VM per user, such as installing packages, running a dev server or executing user code, run client-side instead, on the user's CPU, with nothing to provision and nothing leaving the browser but package downloads and the project's own requests. Mimic is open source under the MIT licence and served from your own origin: no vendor service, no API key, no usage limits.
Three ways to run a user's Node.js project from a web app:
| Cloud VM or container | WebContainers | Mimic | |
|---|---|---|---|
| Licence | A hosted service's terms, or infrastructure you run | The vendor's licence and terms | MIT: self-hosted, no API key, no usage limits |
| Where the project runs | A remote machine per user | The user's tab; the runtime served by the vendor | The user's tab; the runtime served from your origin |
| Startup | Provision or wake a machine | No machine; installs use the user's CPU | No machine; installs use the user's CPU |
| Server cost per user | A machine per active user | None beyond hosting the page | None beyond hosting the page |
| Isolation | A VM or container | The browser's sandbox | A cross-origin-isolated tab, optionally a separate preview origin |
| Limits | Anything Linux runs, Docker included | No native binaries or Docker; a tab's memory | No native binaries or Docker; a tab's memory |
sh -c and the shell scripts package scripts use, with common commands such as
ls, cp and sed.npm install @mimic-js/runtime
import { Mimic } from '@mimic-js/runtime';
const container = await Mimic.boot();
await container.fs.mount({
'server.mjs': {
file: {
contents: `
import http from 'node:http';
http.createServer((request, response) => response.end('hello')).listen(3000);
`
}
}
});
container.endpoints.on('published', (endpoint) => {
document.querySelector('iframe').src = endpoint.url;
});
const server = await container.spawn('node', ['server.mjs']);
server.stdout.pipeTo(new WritableStream({ write: (chunk) => console.log(new TextDecoder().decode(chunk)) }));
// Later: server.kill(); await container.teardown();
One container runs per page at a time.
The page that calls boot() must be cross-origin isolated, so serve it (and the
package's dist/assets) with these headers:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp (or credentialless)
boot() rejects with an error naming them when they are missing. With Vite, the
plugin sends them from vite dev and vite preview:
import { mimic } from '@mimic-js/runtime/vite';
export default defineConfig({ plugins: [mimic()] });
The package README covers the rest: webpack, use without a bundler, production hosting, and the preview origin.
Requires Node 22 and pnpm 11.
pnpm install
pnpm run dev # start the site and its playground at http://localhost:5173
pnpm run test:build # build and typecheck every project
pnpm run test:unit # Vitest unit tests of the runtime
pnpm run test:e2e # Playwright browser tests, including every Compatibility Claim
pnpm run package:check # build the package and check what it would publish
docs/README.md maps the rest of the documentation, including the
architecture decisions under docs/adr/.
Mimic needs a cross-origin-isolated page (for SharedArrayBuffer), Web Workers
and Service Workers. The Compatibility Claims run in Chromium. Chromium and
Firefox support both embedder policies; Safari needs require-corp, as it does
not support credentialless. The package README explains
what each embedder policy changes for the rest of your page.