a pds written in elixir tempest.desertthunder.dev
elixir phoenix atproto pds
tempest docs reference storage-sqlite.md
1.9 kB
Markdown
at commit be6053a4


title: SQLite Storage updated: 2026-05-31 #

Tempest uses SQLite as the default storage backend for a small self-hosted PDS. The design favors inspectable local files over a required external database.

Concepts #

A PDS stores several kinds of state:

  • account/auth state: who can act as whom
  • repository state: signed record blocks and commits
  • sequencer state: global event order for firehose consumers
  • blob state: uploaded bytes and whether records currently reference them

Repository data is public and content-addressed, but account/session keys and operator secrets are private operational state.

Data directory #

TEMPEST_DATA_DIR owns all local persistent state. Development defaults to priv/tempest_dev.

Typical layout:

<TEMPEST_DATA_DIR>/
  account.sqlite
  sequencer.sqlite
  repos/
    <normalized-did>.sqlite
  blobs/
    <normalized-did>/
      <cid>

Databases #

account.sqlite is managed through Ecto and stores account-oriented state: accounts, sessions, signing keys, app passwords, OAuth data, and blob metadata.

sequencer.sqlite is a raw SQLite database for the monotonic PDS-wide event sequence. It is the durable source for firehose cursors.

Each hosted DID gets a separate repo database under repos/. Repo databases store blocks, current record indexes, commits, and repo metadata.

Operational notes #

SQLite runs with WAL where configured. Repo writes are serialized per DID and use explicit transaction boundaries so a record write cannot become visible without its corresponding commit metadata.

Backups must include account.sqlite, sequencer.sqlite, repos/, blobs/, and any WAL files or checkpointed equivalents.

Verification #

hurl --test --variable base_url=http://localhost:4000 test/smoke/health.hurl

The health response includes the active data directory, account DB, sequencer DB, and writability status.