# Module workers Each worker runs on its own thread and V8 isolate. Workers have the same module loader, TypeScript support, built-in modules, and network APIs as the parent. ```ts import { avril } from "avril:std"; const worker = new Worker(new URL("./worker.ts", import.meta.url), { type: "module", name: "background", [avril]: { caps: { env: false, write: false, net: { allow: ["example.com:443"] }, }, }, }); worker.onmessage = ({ data }) => { console.log(data); worker.terminate(); }; worker.onerror = (event) => { event.preventDefault(); console.error(event.message); }; worker.postMessage({ value: 42 }); ``` In `worker.ts`: ```ts onmessage = ({ data }) => { postMessage({ doubled: data.value * 2 }); close(); }; ``` Only `type: "module"` is supported. Relative worker URLs resolve against the parent's entry URL; `new URL("./worker.ts", import.meta.url)` is preferable when the constructor is called from an imported module. A worker exposes `self`, `name`, read-only `location`, `postMessage`, `onmessage`, `onmessageerror`, and `close`. Workers may create nested workers. ## Capabilities and environment The `avril` export is `Symbol.for("runtime:avril")` and keys avril-specific worker options. Omitting `caps` inherits the parent's capabilities. The object uses the same restrictions as `pledge`: `net`, `env`, `sys`, `read`, `write`, `jsExec`, and `run`, each either `false` or `{ allow, deny }`. Restrictions apply before the entry module loads. They cannot grant authority that the parent lacks. A worker receives an independent snapshot of its parent's effective capabilities at construction; later parent or ancestor pledges do not restrict existing workers or their descendants, while workers spawned later from the pledged context inherit the narrowed policy. A worker's own pledge does not restrict its parent or siblings. Workers receive an independent snapshot of the parent's runtime environment at construction time. Environment mutations are local, and access remains subject to capabilities. Worker standard input is unavailable; console and standard output/error remain available. ## Messages and transfers `postMessage(value, transfer)` and `postMessage(value, { transfer })` support: - Structured-clone graphs, including cycles, maps, sets, typed arrays, errors, blobs, files, DOM exceptions, crypto keys, and WebAssembly modules. - `ArrayBuffer` transfers, which detach the sender's buffer. - `SharedArrayBuffer` and `Atomics` for shared memory. - `MessagePort` transfers, including queued messages and retransfers. - `ReadableStream`, `WritableStream`, and `TransformStream` transfers. Stream transfers lock the sender's stream. Chunks and rejection/cancellation reasons are cloned across the message channel; demand and write acknowledgments preserve backpressure. Byte streams become default readable streams at the destination. Closing an endpoint or terminating its owner rejects outstanding remote operations. ```ts const channel = new MessageChannel(); channel.port1.onmessage = ({ data }) => console.log(data); worker.postMessage({ port: channel.port2 }, [channel.port2]); const bytes = new Uint8Array([1, 2, 3]); worker.postMessage(bytes, [bytes.buffer]); ``` Workers keep their parent alive until they close, fail, or are terminated. `close()` finishes the current turn and discards future incoming tasks; `terminate()` interrupts execution, including CPU-bound JavaScript. Parent teardown terminates and joins its workers recursively.