Files & storage
There are two kinds of files in a doze project: what you write (a little config you commit) and what doze manages (engine binaries, data, sockets, and logs it keeps out of your way). This page explains exactly where everything lives, what to commit versus ignore, how to split your config across files, and how to reset or clean things up.
The short version
Section titled “The short version”my-app/ doze.hcl # you write this — your declared instances (commit) doze.lock # doze writes this — resolved versions + checksums (commit) *.doze.hcl # optional — extra config, split by topic (commit) .doze/ # doze writes this — runtime manifest (gitignore)Everything heavy — the actual Postgres/Redis binaries and your databases’ data —
lives outside your project, in a shared home at ~/.doze. Your repo stays
tiny.
What you write
Section titled “What you write”doze.hcl
Section titled “doze.hcl”Your declared instances and root settings. The one file you really author. See the configuration reference.
*.doze.hcl (optional)
Section titled “*.doze.hcl (optional)”You can split instances across sibling *.doze.hcl files — doze merges them
automatically. See breaking config into files.
doze.lock — commit it
Section titled “doze.lock — commit it”doze.lock is doze’s package-lock.json, and it pins three layers of the
supply chain, right next to doze.hcl:
engines: # engine binaries: version = 16 -> 16.14.0 + per-platform SHA-256 postgres: "16": { resolved: 16.14.0, hashes: { … } }modules: # the plugin providing each engine: release, plugin doze/postgres: # protocol, supported engine versions, all-platform hashes version: 0.2.1 protocol: 1 engines: ["14", "15", "16", "17", "18"] hashes: { … }keys: # each registry namespace's ed25519 publisher key, doze: Nu5y8mbjYv7… # pinned on first use — a swapped key is a hard errorCommit it. Every teammate and your CI then run byte-identical modules and
engine binaries, verified against the same publisher key. Module pins never
move on their own — doze modules upgrade moves them, and prints a reminder to
commit. See Managing binaries.
What doze manages
Section titled “What doze manages”The home — ~/.doze (shared across all your projects)
Section titled “The home — ~/.doze (shared across all your projects)”One machine-wide directory holds the engine toolchains and per-project state, laid out like moonrepo’s proto:
~/.doze/ postgres/ # engine toolchains, downloaded once… 16.14.0-aarch64-apple-darwin/bin # …and shared by every project _templates/16.14.0/ # copy-on-write boot template (initdb once) valkey/ kvrocks/ documentdb/ # same idea per engine cache/ # transient downloads tls/ # auto-generated self-signed cert (shared) projects/ # per-project state (see below) my-app-1a2b3c4d/ other-app-9f8e7d6c/Because toolchains live here and are content-addressed, ten projects that all use
Postgres 16.14 share one download. Relocate the whole home with $DOZE_HOME
or the home setting.
Per-project state — ~/.doze/projects/<slug>/
Section titled “Per-project state — ~/.doze/projects/<slug>/”Each project gets its own namespaced subdirectory (the slug is your project folder
name plus a short hash of its path, so two app folders never collide):
~/.doze/projects/my-app-1a2b3c4d/ clusters/ # each instance's DATA lives here app/ # the `app` Postgres data directory cache/ # the `cache` Valkey data directory run/ # runtime files doze.pid # the daemon's pid doze.admin.sock # the control socket the CLI/TUI talk to doze.log # the daemon log (doze logs) app/ # the `app` backend's private socket backend-app.pid # for crash/orphan reconciliationFind a project’s directory any time:
doze doctor # the `project` line prints this path.doze/endpoints.yaml (project-local)
Section titled “.doze/endpoints.yaml (project-local)”When the daemon is up it writes .doze/endpoints.yaml next to your doze.hcl —
the current address and connection string for each instance, for other tooling to
read. It’s regenerated on demand, so gitignore it.
Putting state somewhere else
Section titled “Putting state somewhere else”By default a project’s state lives under the shared home. Two overrides:
home = "~/.doze" # relocate the shared tool store + cache (or set $DOZE_HOME)data_dir = "./.doze-state" # keep THIS project's data inside the repo insteaddata_dirmoves clusters/sockets/logs for this project. Pointing it at a path inside your repo (e.g../.doze-state) keeps everything self-contained — just gitignore it. Handy for throwaway sandboxes or fully isolated CI.home/$DOZE_HOMEmoves the shared, cross-project tool store.
Commit vs ignore
Section titled “Commit vs ignore”| File | Commit? | Why |
|---|---|---|
doze.hcl | ✅ | your declared environment |
doze.lock | ✅ | byte-identical binaries for the whole team |
*.doze.hcl | ✅ | shared split config |
local.doze.hcl | ❌ | per-developer overrides (see below) |
.doze/ | ❌ | regenerated runtime manifest |
data_dir if inside the repo | ❌ | actual database data |
A typical .gitignore:
.doze/local.doze.hcl.doze-state/ # only if you set data_dir to an in-repo pathBreaking config into files
Section titled “Breaking config into files”For anything past a couple of instances, split doze.hcl into sibling
*.doze.hcl files. doze loads doze.hcl first (it holds the root settings), then
merges every *.doze.hcl beside it in sorted order — it’s all one config. (A plain
*.hcl sibling is left alone; only the *.doze.hcl suffix is auto-merged.)
my-app/ doze.hcl # root settings (listen/defaults/tls) + core instances databases.doze.hcl # postgres instances cache.doze.hcl # valkey / kvrocks aws.doze.hcl # s3 / sqs / sns# doze.hcl — root settings live here, and only heredefaults { idle_timeout = "5m" }
postgres "app" { version = 16 role "app" { password = "app" }}# aws.doze.hcl — just more instancess3 "media" { bucket "uploads" {}}sqs "jobs" { queue "emails" {}}doze status # shows app (from doze.hcl) and media + jobs (from aws.doze.hcl)doze doctor # validates the merged wholeRules of thumb
- Root settings (
listen,home,data_dir,defaults,tls) belong indoze.hcl. A duplicatedefaults/tlsacross files is a (clearly reported) error. - Instance blocks can live in any file; names must be unique across all of them.
- Or point
--configat a directory to merge every*.hclin it:Terminal window doze --config ./config status - Errors are reported with the file, line, and a snippet — including cross-file duplicates and unknown blocks (with a “did you mean?” hint).
Per-developer overrides
Section titled “Per-developer overrides”Keep shared instances committed in doze.hcl, and let each developer add personal
ones in a gitignored local.doze.hcl:
# local.doze.hcl (gitignored — yours alone)postgres "scratch" { version = 17 role "me" { password = "me" }}Everyone shares the same baseline; your scratch instance never touches the team’s config.
Multiple projects on one machine
Section titled “Multiple projects on one machine”Run doze from each project directory and they stay completely independent — own
data, own endpoints, own daemon — while sharing the downloaded toolchains
under ~/.doze. You can have Postgres 14 in one repo and 17 in another with zero
conflict.
Resetting & cleaning up
Section titled “Resetting & cleaning up”# Put an instance to sleep now (data is kept; next connect re-boots it)doze sleep app
# Wipe one instance's data and start fresh (re-provisions + converges on next boot)doze reset app
# Nuke a whole project's state (stop the daemon first)doze downrm -rf "$(doze doctor | awk '/project/{print $3}')"
# Reclaim disk from downloads / unused toolchainsrm -rf ~/.doze/cacherm -rf ~/.doze/postgres/15.18.0-* # an engine version you no longer useNothing here touches your doze.hcl or doze.lock — recreate the data any time
by connecting again.
Next: the configuration reference for every field, or recipes for concrete setups.