[API reference](https://evolu.dev/docs/api-reference) › [@evolu/common](https://evolu.dev/docs/api-reference/common) › [Worker](https://evolu.dev/docs/api-reference/common/Worker) › MessageChannel

Defined in: [packages/common/src/Worker.ts:226](https://github.com/evoluhq/evolu/blob/b6ade4b22d4be1758761a2712668e870d3e602c7/packages/common/src/Worker.ts#L226)

Typed, disposable MessageChannel.

Creates two entangled ports: keep one and transfer the other (e.g., to a
SharedWorker via `postMessage` with `transfer`). Messages sent to one port
are received by the other.

Messages are queued until `onMessage` is assigned, enabling safe async
initialization. The sender can post messages immediately while the receiver
performs async setup — no manual buffering required.

For one-way communication, omit `Output` (defaults to `never`).

Transfer a channel port to a SharedWorker and use the retained port
immediately:

```ts
import {
  assertEqual,
  createMessageChannel,
  createMessagePort,
  createSharedWorker,
  type NativeMessagePort,
} from "@evolu/common";

interface Query {
  readonly text: string;
}
interface QueryResult {
  readonly rows: ReadonlyArray<string>;
}
interface ConnectToEvolu {
  readonly port: NativeMessagePort<QueryResult, Query>;
}

const response = Promise.withResolvers<QueryResult>();
using sharedWorker = createSharedWorker<ConnectToEvolu>((self) => {
  self.onConnect = (controlPort) => {
    controlPort.onMessage = ({ port }) => {
      const workerQueries = createMessagePort<QueryResult, Query>(port);
      workerQueries.onMessage = (query) => {
        workerQueries.postMessage({ rows: [query.text] });
        workerQueries[Symbol.dispose]();
      };
    };
  };
});
using queryChannel = createMessageChannel<Query, QueryResult>();
queryChannel.port1.onMessage = response.resolve;

// The main thread retains port1 and transfers the worker-facing port2.
sharedWorker.port.postMessage({ port: queryChannel.port2.native }, [
  queryChannel.port2.native,
]);
queryChannel.port1.postMessage({ text: "all todos" });

assertEqual(await response.promise, { rows: ["all todos"] });
```

On the worker side, attach the handler after asynchronous initialization;
messages sent earlier remain queued:

```ts
import {
  assertEqual,
  createMessageChannel,
  createMessagePort,
} from "@evolu/common";

interface Query {
  readonly text: string;
}

using channel = createMessageChannel<Query>();
using workerPort = createMessagePort<never, Query>(channel.port2.native);
const received: Array<Query> = [];
const allReceived = Promise.withResolvers<void>();
// The main thread can send several messages while the worker initializes.
channel.port1.postMessage({ text: "all todos" });
channel.port1.postMessage({ text: "completed todos" });

await Promise.resolve();
workerPort.onMessage = (query) => {
  received.push(query);
  if (received.length === 2) allReceived.resolve();
};
await allReceived.promise;

assertEqual(received, [{ text: "all todos" }, { text: "completed todos" }]);
```

## See

https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel

## Extends

- [`Disposable`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html#using-declarations-and-explicit-resource-management)

## Extended by

- [`TestMessageChannel`](https://evolu.dev/docs/api-reference/common/Worker/interfaces/TestMessageChannel)

## Methods

<a id="dispose"></a>

### \[dispose\]()

```ts
dispose: void;
```

Defined in: node\_modules/@typescript/old/lib/lib.esnext.disposable.d.ts:34

#### Inherited from

```ts
Disposable.[dispose]
```

## Properties

<a id="port1"></a>

### port1

```ts
readonly port1: MessagePort<Input, Output>;
```

Defined in: [packages/common/src/Worker.ts:228](https://github.com/evoluhq/evolu/blob/b6ade4b22d4be1758761a2712668e870d3e602c7/packages/common/src/Worker.ts#L228)

The first port of the channel.

---

<a id="port2"></a>

### port2

```ts
readonly port2: MessagePort<Output, Input>;
```

Defined in: [packages/common/src/Worker.ts:231](https://github.com/evoluhq/evolu/blob/b6ade4b22d4be1758761a2712668e870d3e602c7/packages/common/src/Worker.ts#L231)

The second port of the channel.