Configuration reference
All configuration is passed to the app container as environment variables — in
the quick-start setup, via the environment: block of docker-compose.yml and
the .env file next to it. Everything except the database password and signing
key is optional; unset features stay quietly off.
Core
| Variable | What it does |
|---|---|
|
Where PostgreSQL is. |
|
Database name and user. |
|
Database password. Set once in |
|
Secret that signs login sessions — any random string of at least 32 characters. Required in practice: if you leave it unset the app generates a throwaway key at each start, which logs everyone out on every restart. |
|
How long a login stays valid. Defaults to |
AI meal estimation (optional)
Estimating a meal from a typed description or a photo is handled by an AI provider that you choose and pay for (or self-host). The app reads a small JSON file listing one or more providers, and the secret keys come from separate environment variables — so no key is ever written into the provider list.
Two variables wire it up:
| Variable | What it does |
|---|---|
|
Path inside the container to your provider-list JSON (below). Unset = AI off. |
|
The API key for a provider whose |
|
How long to wait on a provider before giving up. Defaults to |
A minimal provider list — one hosted provider (Anthropic’s Claude) that handles both typed text and photos:
{
"ai": {
"providers": [
{
"name": "claude",
"convention": "anthropic",
"capabilities": ["text", "vision"],
"baseUrl": "https://api.anthropic.com",
"model": "claude-haiku-4-5-20251001",
"order": 1,
"enabled": true,
"keyRef": "claude"
}
]
}
}
Each provider entry:
-
convention— the wire protocol:anthropic, oropenai(which also covers local OpenAI-compatible servers like Ollama and vLLM). -
capabilities—text,vision, or both. A typed meal needs atextprovider; a photo needs avisionone. -
order— lower runs first within each capability; if a provider fails, the app falls through to the next one that can do the job. -
keyRef— names theAI_KEY_<NAME>variable holding this provider’s key; omit it for a key-less local server.
To use the file, save it next to your compose file (say ai-providers.json),
mount it read-only into the container, and point AI_CONFIG_FILE at it:
services:
app:
environment:
AI_CONFIG_FILE: /app/ai-providers.json
AI_KEY_CLAUDE: ${AI_KEY_CLAUDE:?set AI_KEY_CLAUDE in .env}
volumes:
- ./ai-providers.json:/app/ai-providers.json:ro
The file is re-read while the app runs, so you can add or reorder providers without a restart. A photo defaults to a vision-capable provider (e.g. Claude); text-only providers such as DeepSeek handle typed descriptions but not images.
Barcode lookup (optional)
| Variable | What it does |
|---|---|
|
|
|
The lookup service. Defaults to |
|
How long to wait on a lookup. Defaults to |
Single sign-on / OIDC (optional)
By default Indigo Swallow uses its own email-and-password login. If you run an OIDC identity provider (Keycloak, Zitadel, Authentik, …), you can put SSO in front of it — the built-in login stays available as a fallback.
| Variable | What it does |
|---|---|
|
Your identity provider’s issuer URL. Blank = SSO off (local login only). |
|
The public/PKCE client id you registered for Indigo Swallow. |
|
The expected |
Users are matched to their existing data by verified email, so an account keeps its history when you move it behind SSO.
Email & notifications (optional)
Needed only if you want release-notification emails. Stays off when unset.
| Variable | What it does |
|---|---|
|
|
|
The address your users reach the app at (e.g. |
|
Your mail server. For Gmail: |
|
Login for the mail server. For Gmail, |
|
The From address on outgoing mail (usually the same as |
|
|
Backups (optional)
The app can write periodic JSON snapshots of user data, in addition to (not instead of) backing up the PostgreSQL volume.
| Variable | What it does |
|---|---|
|
|
|
How often, e.g. |
|
Where snapshots are written inside the container (default |
|
How many snapshots to retain before pruning the oldest. |
Logs & traces (optional)
The app always logs to the container’s console (docker compose logs app) and
to a rolling file inside the container — you don’t need any of this. Set these
only if you want logs/traces in your own observability stack.
| Variable | What it does |
|---|---|
|
Ship logs to a Seq server (e.g. |
|
Send traces to any OTLP collector (Jaeger, Grafana Tempo/Alloy, an OTel
Collector). Give the collector’s base HTTP URL, e.g. |