gossamer/worker

A script running on a separate thread. Write the worker as a Gleam module exporting main(), then spawn it with new. Inside the worker script, use gossamer/worker_parent to communicate with the parent thread.

Wrap third-party JavaScript workers in a Gleam module via FFI and spawn them through new — gossamer doesn’t expose a raw-URL constructor because non-Gleam workers don’t fit gossamer’s Result-driven error model.

Send messages to a running worker with post_message and stop it with terminate.

Sending Gleam values

Values cross via structured-clone and arrive on the worker side as Dynamic. See gossamer/message_port for what round-trips cleanly and how to decode the received data.

Transferring ports

A MessagePort reachable from the data passed to post_message is automatically detached on this side and re-attached inside the worker — the message and any ports ride a single atomic call. Transferred ports are no longer usable on the sender. To extract a transferred port from the received Dynamic, use message_port.from_dynamic.

Types

The configuration for a Worker.

pub opaque type Builder

A separate-thread script.

See Worker on MDN.

pub type Worker

Values

pub fn build(builder: Builder) -> Result(Worker, Nil)

Spawns the worker from the configured Builder. Returns an error if the runtime rejects the URL or the worker constructor fails synchronously. Asynchronous loading failures (missing script, syntax error in the script, etc.) are not surfaced — write worker scripts in Gleam to keep them within the language’s Result-driven error model.

pub fn new(module: String) -> Builder

Creates a Builder for a worker that runs the main() function of the named Gleam module. module is the qualified Gleam module name — the same name used in import statements (for example, "my_app/worker"). The first path segment is taken as the package name, matching Gleam’s JavaScript build layout where modules live under build/dev/javascript/<package>/<module>.mjs.

Examples

// For `my_app/worker.gleam` in package `my_app`:
let assert Ok(w) =
  worker.new("my_app/worker")
  |> worker.with_on_message(fn(data, worker) {
    // can reply via `worker.post_message(worker, ...)`
  })
  |> worker.build
pub fn post_message(worker: Worker, data: a) -> Result(Nil, Nil)

Sends data to the worker. Any MessagePort reachable from data is detached on this side and arrives inside the worker at its position in the data structure. Returns an error if data can’t be serialized by the structured-clone algorithm — functions, symbols, and most class instances are not cloneable.

pub fn terminate(worker: Worker) -> Nil

Stops the worker thread immediately. Any queued messages are discarded and the worker’s script is not given a chance to clean up.

pub fn with_name(builder: Builder, name: String) -> Builder

Sets the worker name, used by debugging tools to identify the thread. Empty by default.

pub fn with_on_message(
  builder: Builder,
  handler: fn(dynamic.Dynamic, Worker) -> a,
) -> Builder

Registers a handler invoked for each message the worker sends back. The handler also receives the Worker so it can reply via post_message. Decode the payload with gleam/dynamic/decode; extract any transferred ports with message_port.from_dynamic. ArrayBuffer payloads are exposed as BitArray; other values pass through unchanged.

Search Document