Matterbridge Logo   Matterbridge on Bun

matterbridge.io Docker Image Size ESM ESM


Run matterbridge with bun

Install matterbridge globally with bun

bun add matterbridge --global --omit=dev

Run matterbridge with bun

bunx --bun matterbridge

Run matterbridge with the bun docker hub image (experimental)

The image (tag bun 69 MB) includes only Matterbridge, using the latest release published on npm. This image is based on oven/bun:slim. Plugins are not included in the image: they will be reinstalled on first run.

docker pull luligu/matterbridge:bun && docker run --name matterbridge -v ~/Matterbridge:/root/Matterbridge -v ~/.matterbridge:/root/.matterbridge -v ~/.mattercert:/root/.mattercert --network host --restart always --stop-timeout 60 -d luligu/matterbridge:bun

Bun local image (development)

The bun image runs Matterbridge directly from the local source files with Bun runtime.

Files

File Purpose
docker/Dockerfile.local.bun The Bun image definition
docker/Dockerfile.local.bun.dockerignore Per-Dockerfile build context (keeps source, drops .git/chip/scripts/…)
docker/entrypoint.local.bun.sh Entrypoint banner (prints the Bun version)

Scripts

npm run docker:build:localbun   # build the image (matterbridge:local-bun)
npm run docker:run:localbun     # run it (container matterbridge-local-bun, port 8283)
npm run docker:exec:localbun    # open a shell in the running container
npm run docker:log:localbun     # follow the container logs

Status

The core bridge runs on Bun: it creates its directories, initializes the Matter node storage, and brings up the server node and endpoints. The web frontend is built and served. See the TODO list below for the known limitations.


Bun port status

The approach is to detect if running in bun with isBun() and switch the package-manager command and global-modules paths to Bun where needed.

Done

Known issue

// Change: FileStorageDriver.js
async #writeAndMoveFile(filepath, valueOrStream) {
  const tmpName = `${filepath}.tmp`;
  await writeFile(tmpName, valueOrStream, { encoding: "utf8", flush: true });
  await rename(tmpName, filepath);
}
// Change: FileStorageDriver.js
import { isBunjs } from '../../util/runtimeChecks.js';
if (isBunjs()) {
  if (typeof valueOrStream === 'string') {
    await writeFile(tmpName, valueOrStream, { encoding: 'utf8', flush: true });
  } else {
    const value = new Uint8Array(await new Response(valueOrStream).arrayBuffer());
    await writeFile(tmpName, value, { flush: true });
  }
  await rename(tmpName, filepath);
  return;
}
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */

import * as assert from 'node:assert';
import { mkdtemp, readFile, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';

import { FileStorageDriver } from '../../src/storage/fs/FileStorageDriver.js';

describe('FileStorageDriver Bun runtime', () => {
  let rootDir: string;

  beforeEach(async () => {
    rootDir = await mkdtemp(join(tmpdir(), 'matterjs-file-storage-bun-test-'));
  });

  afterEach(async () => {
    await rm(rootDir, { recursive: true, force: true });
  });

  it('uses the Bun write path for string and stream values', async () => {
    const previousBun = process.versions.bun;
    Object.defineProperty(process.versions, 'bun', { value: '1', configurable: true });
    try {
      const storage = new FileStorageDriver(rootDir);
      await storage.initialize();
      await storage.set(['context'], 'text', 'value');
      assert.equal(await storage.get(['context'], 'text'), 'value');

      await storage.writeBlobFromStream(
        ['context'],
        'blob',
        new ReadableStream<Uint8Array>({
          start(controller) {
            controller.enqueue(new Uint8Array([1, 2, 3]));
            controller.close();
          },
        }),
      );
      await storage.close();

      const file = await readFile(join(rootDir, 'context.blob'));
      assert.deepEqual(new Uint8Array(file), new Uint8Array([1, 2, 3]));
    } finally {
      if (previousBun === undefined) {
        delete process.versions.bun;
      } else {
        Object.defineProperty(process.versions, 'bun', { value: previousBun, configurable: true });
      }
    }
  });
});