tags: development references:
SilverBullet development can happen at various level.
At its most basic level, you can do a lot using [Space Lua](Space Lua). If this does not give enough power, you can upgrade to Plugs. If that doesn’t suffice, you can contribute to SilverBullet’s core (see below).
SilverBullet’s client is written in TypeScript and built on top of the excellent CodeMirror 6 editor component. Additional UI is built using Preact. ES Build is used to build the frontend.
Plugs are also written in TypeScript.
The SilverBullet server is written in Rust (a Cargo workspace).
client/: The SilverBullet client, implemented with TypeScriptserver/: The SilverBullet server library (Rust): HTTP router, handlers, auth, runtime seamserver-common/: Shared Rust crate (space primitives, shared types)server-runtime-chrome/: Headless-Chrome runtime backend (Rust)bin/silverbullet/: The standalone server binary (Rust)bin/sb/: The sb command-line client (Rust)plugs: Set of built-in plugs that are distributed with SilverBulletlibraries: A set of libraries (space scripts, page templates, slash templates) distributed with SilverBulletplug-api/: Useful APIs for use in plugs
lib/: Useful libraries to be used in plugssyscalls/: TypeScript wrappers around syscallstypes/: Various (client) types that can be references from plugsbin/plug-compile.ts: the plug compilerscripts/: Useful scriptsdocs/: silverbullet.md website contentRequirements:
Install dependencies once:
make setup
SilverBullet has two halves you rebuild independently — knowing which one you changed saves time:
server/, server-common/, server-runtime-chrome/, bin/silverbullet/) is a compiled binary.client/) is built by ESBuild into client_bundle/, which the server serves.Run the server in development with cargo run. A debug build serves the client bundle live from client_bundle/ on disk (a release build embeds it). Use SB_DISABLE_SERVICE_WORKER=1 so the service worker doesn't cache stale assets:
SB_DISABLE_SERVICE_WORKER=1 cargo run -p silverbullet -- <PATH-TO-YOUR-SPACE>
To pass arguments like -p or -L, put them after --:
SB_DISABLE_SERVICE_WORKER=1 cargo run -p silverbullet -- -L 0.0.0.0 <PATH-TO-YOUR-SPACE>
When you change the server (any Rust code): rebuild and restart it — stop the process and re-run cargo run (it recompiles). A running server does not pick up source changes.
When you change only the client (TypeScript in client/): you do not need to restart the server. Rebuild just the client and reload the page in your browser — the debug server serves the new bundle from disk:
npm run build:client # rebuild only the client; then reload the page
(For plugs, use npm run build:plugs; npm run build does both.)
To build a self-contained release binary (with the client bundle embedded) and run it:
make build-rs # -> target/release/silverbullet
./target/release/silverbullet <PATH-TO-YOUR-SPACE>
# Clean all generated files
make clean
# Typecheck and lint all code
make check
# Format all code
make fmt
# Run all tests
make test
Multi-arch (amd64 + arm64 + arm/v7) Docker images are published to Docker Hub
and the GitHub Container Registry. The edge channel is rebuilt on every push
to main; stable images come from git tags:
zefhemel/silverbullet:v2 (edge) / :latest + :X.Y.Z (stable) — the server
(Alpine, static musl binary)…:v2-runtime-api (edge) / :latest-runtime-api + :X.Y.Z-runtime-api
(stable) — the same, plus Chromium for the server-side Lua runtime
(/.runtime/*)Both images are mirrored to ghcr.io/silverbulletmd/silverbullet under the same
tags.
To run one:
docker run -p 3000:3000 -v <PATH-TO-YOUR-SPACE>:/space zefhemel/silverbullet:v2
These are built by .github/workflows/ci.yml, which cross-compiles the binary
natively (cargo build --target with installed musl cross-toolchains) and copies
it into a small Alpine image.