Skip to content

Configuration and paths

works

Config values come from, in decreasing priority:

  1. Command-line flags.
  2. HOBBY_* environment variables.
  3. A hobby.json found by walking up from the current directory.
  4. Defaults.

Paths are separate and simpler: they always come from $HOBBY_HOME, or ~/.hobby if that is unset.

Key Env Default What
image postgres:18-alpine The Postgres image
proxyPort HOBBY_PROXY_PORT 5432 Where the wire-protocol proxy listens
studioPort HOBBY_STUDIO_PORT 8443 Studio
apiPort 7432 The daemon API, loopback only
httpPort 7433 The HTTP wake router
queuePort 7434 The queue endpoint
domain localhost The base domain apps and workers get hostnames under
sleepAfterSeconds 300 Idle time before a resource sleeps
wakeTimeoutMs 30000 How long a wake may take before it is a failure
readinessPollMs 25 How often readiness is polled during a wake
caddyEnabled false Whether the Caddy front door runs at all
caddyAdminPort 2019 Caddy’s admin API, loopback only
caddyStudioHost null The public hostname for Studio. null publishes no Studio route

A minimal hobby.json:

{
"sleepAfterSeconds": 900,
"caddyEnabled": true,
"domain": "example.com"
}
~/.hobby/
state.db the daemon's record of everything
hobby.sock the unix socket for the CLI and MCP
hobby.json config
projects/
<project>/
<resource>/
pgdata/18/docker postgres: a plain PGDATA
bundle/ worker: the built script and its manifest
state/ worker: KV, R2, D1, cache
do/ worker: Durable Object sqlite
queue/messages.sqlite queue: the messages

An app has no directory: it is stateless by design.

$HOBBY_HOME moves all of it. That is the supported way to keep state on a different disk.

Postgres 18’s official image refuses to start when a bind mount lands directly on what used to be PGDATA. The mount point is therefore the postgres home directory, and the image’s entrypoint places the real data directory in a subdirectory named for the major version. resolvePgdataPath in packages/core/src/config.ts is the one place that is written down; everything needing the true on-disk path derives it from there rather than hardcoding the subdirectory.

Resources that need a directly reachable host port are allocated one from 15000 to 19999. That is the port hobby ls prints. It is not the port you normally dial: for Postgres that is the proxy on 5432, which is what makes wake work.

Read by the bootstrap script, not by the daemon:

Variable Default What
HOBBY_SRC_DIR ~/.hobby/src Where the checkout lives
HOBBY_REPO_REF main Branch or tag to install
HOBBY_REPO_URL the canonical repository Where to clone from
HOBBY_BIN_DIR /usr/local/bin or ~/.local/bin Where the launcher goes