Getting started
Let’s build something. In about ten minutes you’ll go from an empty directory to a real local backend — a Postgres database and a cache — with the engines booting on demand and sleeping when you’re done. We’ll talk through what you’re seeing at each step, so you finish this knowing not just what to type but why it works the way it does.
Prerequisites: macOS (Apple Silicon) or Linux (x86-64 / arm64). That’s the whole list — you won’t install Postgres, Redis, or any other engine; doze fetches those for you. Hit a snag anywhere? Troubleshooting has your back.
1. Install
Section titled “1. Install”doze is a single binary with nothing else to set up:
brew install doze-dev/tap/dozedoze version(Prefer mise, a raw download, or go install? All of them are on the
install page — pick whichever fits your setup.)
You do not install Postgres, Redis, or anything else — doze fetches the real
engine binaries for you on first use and caches them under ~/.doze.
2. Describe what you need
Section titled “2. Describe what you need”doze reads a doze.hcl file. Scaffold one:
mkdir myapp && cd myappdoze initOpen doze.hcl and trim it down to one database to start:
postgres "app" { version = 16 role "app" { password = "app" } grant { role = "app" database = "app" privileges = ["ALL"] }}You’ve just declared an instance named app: Postgres 16, with a login role
app that owns a database app. You haven’t started anything yet — this is the
desired end state, not a command.
Sanity-check it any time:
doze doctor# ✓ config doze.hcl parses cleanly# ✓ postgres/app 16 (not pinned; resolves on first use)# ✓ daemon stopped (starts on first connect, or `doze up`)3. Connect — and watch it boot itself
Section titled “3. Connect — and watch it boot itself”Open a SQL shell:
doze shell appThe first time, this does a lot for you, transparently:
- fetches the postgres module — the signed plugin that provides the engine —
from the registry, verifies its signature, and pins it in
doze.lock(doze prints a nudge to commit the lockfile: do), - resolves and downloads the real Postgres 16 binaries (once, cached),
- initializes a fresh data directory,
- boots the server,
- converges your declared shape — creates the
approle, theappdatabase, and grants — then - drops you into
psql.
psql (16.14)Type "help" for help.
app=#It’s a real, unmodified Postgres. Try \du and you’ll see your app role; \l
shows the app database. Quit with \q.
doze converges structure, not data. It created the database, role, and grants you declared — it did not insert any rows. Your app’s migrations own the schema and data; doze owns the scaffolding around them.
4. See the magic: lazy boot and idle reap
Section titled “4. See the magic: lazy boot and idle reap”See your declared instances and their state (everything’s asleep until you connect):
doze status# NAME ENGINE STATE CONNS RAM UPTIME ENDPOINT# app postgres idle 0 5M 3s 127.0.0.1:6432app is idle — booted, but with no live connections. Connect to it:
psql "postgresql://app:app@127.0.0.1:6432/app" -c "select 1"While that query runs, doze status shows the instance active with a live
connection. Close the client, wait for the idle timeout (5 minutes by default),
and it reaps back to zero — the process exits, RAM goes back to your laptop,
and the next connection boots it again. The reap keeps the data directory, so
waking back up is sub-second (only the very first boot of an instance takes a
few seconds) — you never have to think about starting or stopping it. See
Waking back up for the full cost model.
You can watch all of this live:
doze dash # an interactive dashboard; select a row to wake/sleep it5. Add a cache
Section titled “5. Add a cache”Real apps need more than a database. Add a Valkey (Redis-compatible) cache — just declare it:
postgres "app" { version = 16 role "app" { password = "app" } grant { role = "app" database = "app" privileges = ["ALL"] }}
valkey "cache" { version = 9 maxmemory = "256mb"}doze status# app postgres idle …# cache valkey reaped … (boots when something connects)Two engines, one file. Each has its own endpoint and its own lifecycle.
6. Wire it into your app
Section titled “6. Wire it into your app”Your app shouldn’t hardcode ports — except it doesn’t have to. Every instance
listens on the explicit port you declared, so its URL is stable and
deterministic. Two honest ways to wire it in:
doze run -- <your dev server> # npm run dev · rails server · go run ./... · python manage.py runserverdoze run just ensures the daemon and your backends are up, then runs your
command — whatever language it’s in. Your app connects to the stable URLs you put
in its config (cold-booting each instance on first connect):
postgresql://app:app@127.0.0.1:5432/app→ theappPostgresredis://127.0.0.1:6379→ thecacheValkey
Drop those straight into your .env, no magic required.
Prefer doze to inject them for you? Declare your app as a
processblock and doze sets each dependency’senv_varto its URL automatically. The daemon also writes the current set to.doze/endpoints.yamlfor other tooling to read.
7. A throwaway database for your tests
Section titled “7. A throwaway database for your tests”Want a clean, real database for a test run? Reset the instance to a fresh slate, then run your suite against it:
doze reset app # wipe app's data; it re-provisions + converges on next bootdoze run -- pytest # ensures backends are up, then runs your testsdoze reset gives you back a pristine app (structure converged, zero rows),
perfect when a run needs a known-clean database.
You’ve got the model
Section titled “You’ve got the model”That’s the whole loop: declare in doze.hcl, use via doze run or a
direct connection to the stable port, and let doze boot on demand and reap
when idle. From here:
- Why doze — the case against docker-compose / native installs, and the footprint numbers behind “quiet laptop.”
- The engines — what Valkey, Kvrocks, and DocumentDB actually are.
- Core concepts — how lazy boot, reaping, convergence, and the proxy actually work.
- Files & storage — where doze keeps everything, what to commit, and how to split your config across files.
- Recipes — roles & grants, FIFO queues, SNS fanout, CI, and much more.
- Configuration reference — every field.