gunnar
Fast setup: the guide · PDF — four lists of commands, one picture per setup.
Features: what is new, with status, source path and commit.
Git server in Rust, with two engine variants: znippy-based (Apache Arrow IPC in a znippy archive) or gix-based (traditional filesystem).
- Built-in replication to a twin gunnar: self-hosted, the twin is any box that reaches the primary (
gunnar control twin join); a gunnar.rs instance's twin runs in the same zone as its main. - Vetra hardware appliance variant: OS-less, hardened kernel.
- Free to host your own.
- The exact same code is hosted at https://gunnar.rs
- NVMe, io_uring, XFS on raid0, OS-less appliance kernel, WireGuard, Prometheus, Git LFS, smart HTTP, OCI, webhooks, replication to a twin, sshsig/ed25519 signed pushes, SLSA-shaped provenance, transparency log.
Building
Anyone can clone the repository read-only, with no registered SSH key:
git clone ssh://anonymous@git.gunnar.rs:2222/nordisk/gunnar.git
cd gunnar
cargo build --release -p gunnar-cli
A lone clone builds the server by itself, with nothing beside it:
git clone ssh://git.gunnar.rs:2222/nordisk/gunnar && cd gunnar && cargo build --release
./target/release/gunnar # serves on loopback; http://127.0.0.1:8080/healthz answers ok
cargo build --release at the root builds the default member, gunnar (the
server: engine-znippy, SSH and smart HTTP with TLS via --http-tls-*; no mimalloc, no company SSO, no monetize: --features mimalloc,sso adds those). The committed
Cargo.lock is the crates.io lock, so cargo build --locked and cargo install --locked --path crates/gunnar-cli --features client work from a lone clone too (cargo xtask lone-clone proves it on every push). The root takes no sibling patch in any checkout.
In an estate checkout, with ../edda, ../znippy, ../Skidbladnir, ../tunnr,
../draupnir and ../monetize beside it, the detached estate workspaces
(gunnar-front, gunnar-monetize-guest, the benches, installtest) build against
those siblings through the [patch.crates-io] in their own manifests, with
--manifest-path.
This page documents gunnar 1.5.1 — the version gunnar --version prints.
License: AGPL-3.0-only, © 2026 Vetra Automation AB and Ignalina ApS (Rickard Ernst Björn Lundin). Commercial
terms: COMMERCIAL-LICENSING.md.
Install the server with cargo
cargo install gunnar
gunnar
A bare gunnar serves on loopback with no configuration: SSH on 127.0.0.1:2222,
smart HTTP on 127.0.0.1:8080, and health at http://127.0.0.1:8080/healthz. The
default build compiles no monetize crate; the other variants are opt-in cargo
features, listed in crates/gunnar/README.md.
Release provenance (SLSA Build L3)
Releases are built by dwarves, the build server, in its isolated release-build mode and carry signed SLSA v1 provenance:
one in-toto statement per release, every artifact by its sha256, signed on the owner's
YubiKey. The bundles are in attestations/, the release key in
slsa/; how to verify (cosign, dwarves or Holger) and what still keeps us below
L3: docs/SLSA.md.
Complexity and measurements
n objects, r refs, e refs in a batch, k batch size, s object size,
|W|/|H| want/have closure. Read off the znippy engine's code.
| operation | znippy |
|---|---|
put_pack | O(bytes), index deferred |
put_refs | O(r) + O(e·log n) |
get | O(log n) + O(s) |
has | O(log n) |
size | O(log n) |
extents | O(k·log n) |
refs | O(r) |
update_ref | O(log r) |
head | O(log r) |
header | O(log n) |
reachable | O(1) map lookup + bitmap OR |
gc | O(n) compact |
Measured. Each row names its date. A dash means no measurement exists.
| measurement | gitea | gix | znippy | date |
|---|---|---|---|---|
| clone, serve wall, 16384 commits | — | 17.7 s | 7.23 s | 2026-09-01 |
| push, receive-pack, 16384 commits | — | 0.80 s | 1.54 s | 2026-09-01 |
| RSS floor, 16384 commits | — | 13.6 MB | 29.2 MB | 2026-09-01 |
reachable, 16384 commits | — | 14.9 s | 5.6 ms | 2026-09-01 |
refs | — | — | 30–50× faster than gix | 2026-09-01 |
header | — | ~5× faster than znippy | — | 2026-09-01 |
| durable 8 KiB push, index included | — | 50 573 µs (library writer, no fsync) | 147.7 µs | 2026-08-07 |
| provision 100 000 users | 77 min, projected | — | 6.1 s | 2026-08-12 |
| ls-remote p50 @ 100 000 users | 27.0 ms | — | 10.0–10.5 ms | 2026-08-12 |
| ls-remote p99 @ 100 000 users | 39–43 ms | — | 102–168 ms | 2026-08-12 |
| ls-remote throughput | 1 140 req/s | — | 2 060–2 320 req/s | 2026-08-12 |
| clone (small), net CPU | 0.033 s | — | 0.010 s | 2026-08-13 |
| clone (small), peak RSS | 113 MB | — | 2 308 MB | 2026-08-13 |
| push (base), net CPU | 0.944 s | — | 0.302 s | 2026-08-13 |
| push (base), server→client bytes | 2.1 kB | — | 1.4 kB | 2026-08-13 |
Conditions: 2026-09-01 rows, the desktop, 5 repetitions plus warm-up, load-1 mean 13.4, both engines in one binary. 2026-08-13 rows, the desktop, 32 cores, 3 interleaved rounds, 8 CPUs and 8192 MB per engine, byte counts taken by a counting relay. 2026-08-12 and 2026-08-07 rows, the desktop.
Thanks
- Its inventors: Vetra Automation AB and Ignalina ApS (Danskjävlarna).
- Ragnar Groot Koerkamp — the ridiculously fast static search tree.
- Christopher Berner — the neat redb.
Contributing, security and changes
- CONTRIBUTING.md: how to get the code, report a bug and propose a change.
- SECURITY.md: how to report a vulnerability privately (gunnar@gunnar.rs).
- CHANGELOG.md: what changed in each release, and the vulnerabilities each one fixed.
Sponsors
None so far — we would love to have one. Contact gunnar@gunnar.rs.
AI-generated details: .nornir/detail.md