Your whole backend. One file. Self-hosted backend in a single binary: collections, REST, auth, realtime, files, hooks, queues and MCP for AI agents. Live demo · Website · Docs · Releases · TypeScript SDK · MCP bridge The live demo is the admin UI on a sample blog. The login is filled in for you, and the data resets every hour. Linux or macOS (detects x64 / arm64, and glibc / musl on Linux): curl -fsSL https://get.vaultbase.dev | sudo sh Windows, in PowerShell: irm https://get.vaultbase.dev/install.ps1 | iex On Linux it installs the latest release to /usr/local/bin/vaultbase, creates a vaultbase service user and a systemd unit, and starts it on :8091. On macOS it installs the binary to /usr/local/bin and you run vaultbase yourself. On Windows it installs to %LOCALAPPDATA%\Programs\Vaultbase and adds it to your PATH. Open http://localhost:8091/_/ for the setup wizard. sudo sh -s -- --verify-sig checks the binary's cosign keyless signature first (needs cosign on PATH). --version vX.Y.Z, --port N, --no-start, --no-systemd, --install-dir DIR are also available. Or download a binary from Releases. From source: bun install bun run build # admin UI + binary → ./vaultbase[.exe] ./vaultbase # serves on :8091 Features Collections + REST — a real table per collection (vb_), 16 field types, base / auth / view collections. Filter, sort, expand, field projection, batch, ETag concurrency Auth — email + password, OAuth2 with PKCE (Google, GitHub, Apple, Microsoft, Discord, GitLab and more, plus generic OIDC), OTP / magic links, MFA / TOTP, anonymous users, admin impersonation Realtime — WebSocket + SSE; subscribe to a collection, a record, one kind of event (posts.create) or *, checked against your API rules Files — local disk, S3 or R2; thumbnails, MIME / size validation, protected files with one-time tokens Server-side logic — hooks, custom routes, cron, queue workers, webhooks, feature flags and push notifications, edited live in the admin UI with Monaco autocomplete, or kept as TypeScript files in a vb_hooks/ folder (with imports and npm packages) that the admin UI edits too MCP for AI agents — built-in Model Context Protocol server; tools generated per collection, scope-gated tokens, every tool call written to the audit log Operations — request logs, admin audit log, record history with point-in-time restore, encrypted fields (AES-GCM), scheduled backups (a file copy on SQLite, pg_dump on Postgres), Prometheus metrics Database — SQLite by default: one file, read worker threads on spare cores. Postgres (VAULTBASE_DATABASE_URL), including several servers on one database. See Databases Security — brute-force lockout, CORS allow-list, password policy with optional HIBP check, SSRF egress guard for hooks One binary — no native deps, admin UI embedded; releases are cosign-signed with CycloneDX SBOMs Runtime: Bun Framework: Elysia DB: SQLite (bun:sqlite), or Postgres (Bun.sql) ORM: Drizzle Admin UI: React 19 + Vite + React Router v7 + Zustand + PrimeReact + Monaco + Quill Configuration (env vars) Production deployment Vaultbase is one process (with read worker threads on SQLite) and does not terminate TLS or compress responses in-process. Both responsibilities belong to a reverse proxy in front of the binary — nginx, Caddy, or Cloudflare. In-process compression was tried and removed: it blocked the event loop on Bun.gzipSync, regressed RPS by ~14%, and doubled p99.9. Recommended topology Client ── HTTPS ──> nginx / Caddy / CF ── HTTP ──> Vaultbase :8091 │ │ │ TLS termination │ Bun + SQLite (WAL) │ gzip / brotli │ Single binary │ HTTP/2 │ │ Rate limit (defense) │ └──────────────────────────────┘ Sample nginx config upstream vaultbase { server 127.0.0.1:8091 keepalive 64; keepalive_timeout 60s; } server { listen 443 ssl http2; server_name api.example.com; ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem; # Compression — handled here, not in Vaultbase. gzip on; gzip_types application/json text/plain; gzip_min_length 1024; gzip_proxied any; gzip_vary on; # WebSocket realtime location /realtime { proxy_pass http://vaultbase; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_read_timeout 86400s; } location / { proxy_pass http://vaultbase; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } Sample Caddy config api.example.com { encode gzip @ws path /realtime reverse_proxy @ws localhost:8091 reverse_proxy localhost:8091 { header_up X-Forwarded-For {client_ip} header_up X-Forwarded-Proto {scheme} } } # Local file vaultbase backup --to /var/backups/vaultbase-$(date +%F).db # Gzip vaultbase backup --to /var/backups/snap.db --gzip # S3 / R2 / B2 (creds via env) AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... \ vaultbase backup --to s3://my-bucket/vb/snap.db AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... R2_ENDPOINT=https://.r2.cloudflarestorage.com \ vaultbase backup --to r2://my-bucket/vb/snap.db --gzip Snapshots are atomic via SQLite's VACUUM INTO — concurrent writers are serialised but not blocked, and the resulting .db file is self-contained (no *-wal / *-shm sidecars to copy alongside). Cron-friendly: 30 3 * * * vaultbase /usr/local/bin/vaultbase backup --to s3://bucket/vb/snap-$(date +\%F).db --gzip --quiet Restore via POST /api/admin/restore with the snapshot bytes (admin only) or by replacing the DB file while the service is stopped. An online restore checks the file first, stops the read workers and the checkpointer while it swaps it, and starts them again; it is refused under cluster mode. A database backup is the records, schema and settings: uploaded files, the hooks folder, .secret / .encryption-key and your environment are separate, so back up / as a whole. Cluster mode (multi-process, deprecated) Cluster mode is deprecated. Read worker threads (on by default) spread SQLite reads over spare cores in one process, and several servers can share one Postgres database; use those. Cluster mode remains for existing setups, without online restore and with If-Match checked per process. A single Bun process is single-threaded — caps at one CPU core. For higher throughput on multi-core hosts, use the cluster orchestrator: # Auto: one worker per available CPU core bun src/cluster.ts # Or explicit count VAULTBASE_WORKERS=4 bun src/cluster.ts # Same via npm script bun run start:cluster The parent process spawns N workers, all sharing port VAULTBASE_PORT via Bun.serve({ reusePort: true }). On Linux the kernel load-balances incoming connections across workers. Workers run identical code; SQLite WAL handles concurrent readers natively. Health check: GET /_/health returns the responding worker's id + pid + uptime — useful to verify load balancing. It only says the process is up; point readiness probes at GET /_/ready, which checks the database, storage, read workers, queues and log writes and answers 503 when the server can't serve. Graceful shutdown: SIGTERM / SIGINT to the parent broadcasts to workers; each drains its log buffer and closes its DB handle. 30s timeout, then SIGKILL. Crashed worker → automatic restart with 1s backoff. Platform notes: Linux: full SO_REUSEPORT load balancing. ~Nx throughput on N cores (real ~0.85x — some contention is unavoidable). macOS and Windows: the port can be shared, but the kernel doesn't distribute connections: one worker takes all of them and the rest sit idle (measured on macOS: 4 workers, one at 100% CPU, three at 0%). Cluster mode runs but does not multiply throughput there. Use it for fault-tolerance (worker auto-restart) only; deploy on Linux for performance. SQLite under cluster mode (Phase 6a — current): All workers open the same DB file. WAL allows concurrent readers; writes serialize on the file lock. Read-heavy workloads scale near-linearly with worker count. Write-heavy workloads may see lock contention — measure before adopting the dedicated-writer-process pattern. Operational notes Run Vaultbase under a process supervisor (systemd, runit, pm2). It does not daemonize itself. Back up / periodically: on SQLite it holds the database, uploads (local storage), the hooks folder and the keys. On Postgres, back up the database with pg_dump (scheduled backups do this when it's installed) and keep / for uploads and the keys. Set VAULTBASE_JWT_SECRET explicitly in production. The auto-generated fallback is per-host and will rotate if /.secret is wiped, invalidating every issued token. Keep VAULTBASE_ENCRYPTION_KEY (or /.encryption-key) with your backups: encrypted values can't be read without it. Several servers on one Postgres database need the same JWT secret and encryption key. Cross-compile bun run build:linux-x64 bun run build:macos-arm64 bun run build:windows-x64 # or all five bun run build:all Output: releases/vaultbase-[.exe] Development bun install && (cd admin && bun install) # the admin has its own dependencies bun run dev # backend on :8091 bun run dev:admin # admin on :5173 (proxies /api → :8091) bun test # backend tests bun run typecheck Note on local bun run build The compile pipeline patches node_modules/imagescript/codecs/node/index.js in place to stub the native encoder (Bun --compile cannot bundle dlopen-able .node binaries — the patched stub keeps top-level imports working in the single-file binary; JPEG/GIF encode paths fall through to PNG / @jsquash codecs). Side effect: after running any bun run build:*, the imagescript native encoder is gone from node_modules and 2 GIF/JPEG-encode tests will fail locally. Restore with: bun install --force CI is unaffected (every workflow run installs fresh). Community and support Questions: Discussions → Q&A Feature ideas and roadmap: Discussions → Ideas, and the roadmap Show what you built: Discussions → Show and tell Bugs: Issues Security: see SECURITY.md; please don't open a public issue.
AI NEWS JOURNAL
Hacker News Show HNAI NEWS / JOURNAL
Show HN: Vaultbase – a self-hosted back end in a single binary
One binary to run and you have a full backend at your fingertips: a database with a REST API, sign-in, realtime, files, server-side hooks and jobs, on SQLite or Postgres. It's MIT licensed. You can try the demo at https://demo.vaultbase.sh (the login is filled in, and it resets every hour). I built it to ship fast. I always tend to write the same logic for any new project, whether it's a side project or a small to medium project for a client. I wanted something my friends and I could work with fast, try new things with, and that's easy to use. Then it became something I really wanted to work on and make as complete as I can for any type of backend. As of writing this post it has 80 releases since May this year and is backed by more than 2,800 tests. I also run security reviews with Claude and fix what they find. It hasn't had an outside audit yet. It was built with the help of Claude, from the codebase to the documentation and fact-checking it against the code. Claude helped speed up the pace, find bugs, and write tests. Vaultbase is pre-1.0, so expect some bugs and issues here and there. I'm working hard to fix each and every one of them. Thank you for taking the time to read this. I'd really appreciate any feedback, even if you didn't like Vaultbase. The demo is yours to try, and it's two commands to run locally. Comments URL: https://news.ycombinator.com/item?id=50448562 Points: 1 # Comments: 0
翻訳サービスが停止中のため原文を表示しています。