Configure your app with pyvolt.toml

Everything on your app's Settings tab (the serve command, release steps, Python version, build step, background workers, and more) can also live in a pyvolt.toml file at the root of your repo. Commit it, and your deploy config is versioned with your code: reviewed in the same pull request, rolled back with the same revert, and reproducible on any environment.

This is entirely optional. If your repo has no pyvolt.toml, nothing changes: your app keeps using the settings from the dashboard exactly as before.

A complete example

[app]
serve   = "gunicorn config.wsgi:application --workers 2 --bind $SOCK"
release = ["python manage.py migrate --noinput"]
release_env = true              # source the app's env vars into release commands
python  = "3.12"                # optional, see "Versions" below

[build]
command = "npm ci && npm run build"
node    = "20"                  # optional, see "Versions" below

[persist]
dirs = ["data"]                 # paths that must survive a deploy

[processes]
worker = "celery -A config worker"
beat   = "celery -A config beat"

[schedule]
cleanup = { command = "python manage.py clearsessions", cron = "0 3 * * *" }

[frontend]
dir = "dist"
passthrough = ["/api", "/admin"]

[env]
required = ["SECRET_KEY"]       # names only, never values

Only include the sections you need. A file with just [app] is perfectly valid.

How it takes over

When the file is present, the keys it sets override the dashboard on every deploy, and those fields show up read-only on the Settings tab with a "Managed by pyvolt.toml" badge. The rule is per key:

  • A key that is in the file is owned by the file. Edit it in the repo.
  • A key that is not in the file keeps working from the dashboard as usual.

So a file that only sets [app] leaves your Processes and Frontend settings fully editable in the dashboard. Remove a key from the file, deploy, and that field hands control back to the dashboard.

The file never writes secrets. [env] required lists variable names only; the values still live in your app's environment (Settings, or pyvolt env).

The sections

[app]

Key What it does
serve The command that runs your web process. Must bind the socket: include --bind $SOCK (gunicorn) or --uds $SOCK_PATH (uvicorn). $APP_MODULE is also substituted.
release A list of commands run on every deploy after the build and before traffic switches over (migrations, collectstatic). Runs in the project dir with your venv on PATH.
release_env true to source the app's environment variables into each release command, so migrate can read DATABASE_URL. Defaults to false: release steps run with a minimal environment.
python The Python version, for example "3.12". Optional, see "Versions".

[build]

Key What it does
command A build step run after dependencies install (for example a front-end build).
node The Node version to install for the build, for example "20". Optional, see "Versions".

[persist]

dirs is a list of paths, relative to your project, that must survive a deploy. Each is stored outside the versioned release and symlinked back in, so a SQLite database or an uploads folder is not wiped when the next release replaces the checkout. Use it for anything your app writes to disk at runtime.

[processes]

A table of name = "command" background workers. Each becomes a supervised service that restarts on crash, on reboot, and on every deploy. When this section is present it defines the complete set of workers: the Processes tab goes read-only, and any worker not listed here (including ones created in the dashboard) is removed on the next deploy, so the file and the running set always match. It's one or the other per app: manage processes in the dashboard, or in the file, not both.

[schedule]

A table of name = { command = "...", cron = "..." } scheduled jobs. cron is a 5-field expression, validated with the same rules as the Scheduler tab. Either TOML shape works:

[schedule]
cleanup = { command = "python manage.py clearsessions", cron = "0 3 * * *" }

[schedule.weekly-report]
command = "python manage.py send_report"
cron    = "0 8 * * 1"

Same complete-set rule as [processes]: when the section is present it defines all of the app's scheduled jobs, the Scheduler tab goes read-only (Run now and View output still work), and any job not listed - including ones created in the dashboard - is removed on the next deploy.

[frontend]

dir is a built static/SPA directory served at the site root, and passthrough is a list of path prefixes (each starting with /) that still proxy to your app. With no [frontend] section, everything proxies to the app.

[env]

required is a list of environment-variable names your app must have. If any is missing, the deploy stops immediately with a clear message, before anything is built. This catches the classic "forgot to set SECRET_KEY" mistake early rather than at runtime.

Versions

python and node are optional. Leave a version out (or omit the key entirely) and the app keeps its current setting:

  • No python uses the app's Python version, which defaults to 3.12 for a new app.

  • No node uses the repo's own Node version files (.node-version, .mise.toml) if present, otherwise the server's default Node.

Set them only when you want to pin an exact version from the repo.

Validate before you commit

The deploy validates the file first and stops on any problem: a syntax error, a key that is not part of the schema (a typo like serv =), or a value of the wrong shape (release must be a list, python must look like a version). The error names the exact problem so you can fix it in one pass.

You can run that same check locally with the CLI before you commit:

pyvolt config validate            # checks ./pyvolt.toml

Starting from your current settings

To turn an app you already configured in the dashboard into a file, export its current settings and commit the result:

pyvolt apps export-config my-app --write     # writes ./pyvolt.toml

Edit the generated file, commit it, and your next deploy runs from the repo.

View this page as markdown - handy as context for your AI tools. Full index at /llms.txt.