Baalda

Scaling and operations

What one instance handles, what Redis buys you, how upgrades and staging work, and what to back up.


The default single-instance deployment scales to hundreds of concurrent users. The cost of an edit is proportional to the number of people live in that vault, not to how many accounts exist, and the vault channel is a stateless relay, so memory is bounded by the documents being edited rather than the documents that exist.

Going beyond one instance

For thousands of concurrent users, redundancy, or zero-downtime rolling deploys, run several instances behind a load balancer and set the same REDIS_URL on all of them.

  • The vault replication channel fans out through Redis pub/sub, so a client can connect to any instance and still receive every document it is allowed to see.
  • The editing path uses the Redis extension, so the same document edited live on two instances stays consistent.
  • No sticky sessions are needed. Clients reconnect with jittered backoff, so a rolling deploy does not stampede.
Local multi-instance testing
cd app/apps/server
docker compose --profile ha up -d redis   # host port 6389
REDIS_URL=redis://localhost:6389 pnpm run dev

Upgrades

Migrations run before the server starts, so an upgrade is a redeploy. With the Compose bundle that is git pull && docker compose up -d --build, and on Railway it is a redeploy from the latest release. The app's behind-the-server notice clears on its next check, within ten minutes, or at once after a restart or reconnect.

A staging instance

Run a second server for a staging build and set DEEP_LINK_SCHEME=baalda-staging on it, so links from production and from staging open the right app on a machine that has both installed.

What to back up

  • Postgres. It holds identity, organizations, permissions, the registry and the binary document store, and attachment bytes too unless you moved them to S3.
  • The S3 bucket, if you use one. It is not covered by a database backup.
  • Nothing on the clients. Every device's vault folder is a full copy of the Markdown, which is the point of the design.
A single-instance server needs none of the Redis setup. Leave REDIS_URL unset and it behaves exactly as before, with Postgres alone.

This page is written from docs/DEPLOY.md and docs/specs/05-vault-sync-engine.md in the repository. Those documents go further, and they are the ones that change first.

Read it on GitHub