DocsEnvironment variables
Docs/Reference

Environment variables

Anvil reads its settings from environment variables, plus the file named by ANVIL_ENV_FILE (variables in the environment win). It refuses to start when a required variable is missing or invalid, and logs a warning for each optional feature that is off. Empty values count as unset, except GIT_SSH_HOST.

Core #

Variable Required Default Secret What it does
ROLE no all all runs the web server and the review worker in one process; web or worker split them.
PORT no 3000 Port the server listens on.
PUBLIC_URL production http://localhost:3000 Anvil's public address, with https. Every link, webhook URL, OAuth redirect, clone URL and the GitHub App's URLs are built from it.
DATABASE_URL yes secret Postgres connection string (Postgres 16 or newer). Migrations run on boot.
SESSION_SECRET production secret Signs sessions and encrypts stored secrets (GitHub App key, hosted Gitea tokens). 32+ characters. Changing it signs everyone out and makes stored secrets unreadable: move it with the database.
DB_POOL_MAX no 10 Most Postgres connections this process opens.
MAX_BODY_MB no 25 Largest request body the API accepts, in MB.
MAX_UPLOAD_MB no 256 Largest upload (git push over HTTPS, release assets), in MB.
ANVIL_ENV_FILE no A KEY=value file read before the environment (variables set in the environment win). The self-host bundle points it at the file the first-run setup writes (Gitea tokens, OAuth client).
NODE_ENV no production in the image. Turns on the production checks (SESSION_SECRET, PUBLIC_URL) and hides DEV_LOGIN.

Instance #

Variable Required Default Secret What it does
INSTANCE_NAME no Anvil Name used in the email sender and the GitHub App Anvil creates.
SERVER_NAME no your server How pages and docs refer to the machine Anvil runs on ("runs on <SERVER_NAME>").
SERVER_LOCATION no (empty) Where that machine is, for the privacy answers on the landing page and in the docs, e.g. Germany. Empty leaves it out.
CONTACT_EMAIL no Address for privacy, security and legal questions, shown in the docs.
CANONICAL_REDIRECT_HOSTS no (empty) Old hostnames of this install (comma-separated). Pages on them redirect to PUBLIC_URL; webhooks and /mcp keep answering. Off when empty.

Git server #

Variable Required Default Secret What it does
GITEA_URL yes Gitea as Anvil reaches it, for the API and git. Can be internal, e.g. http://gitea:3000.
GITEA_PUBLIC_URL no Gitea as browsers reach it ("Continue with Gitea", links). Defaults to GITEA_URL.
GITEA_TOKEN yes secret Token of the bot user (scopes read:repository, write:repository, write:issue, read:user). Written by the first-run setup.
GITEA_WEBHOOK_SECRET yes secret Signs Gitea's system webhook to <PUBLIC_URL>/api/webhooks/gitea. 16+ characters.
BOT_USERNAME no anvil The bot's Gitea username; people mention it as @<name> in pull requests.
BOT_ALIASES no reviewer Other @names the bot answers to (comma-separated), e.g. a name it had before.
GITEA_OAUTH_CLIENT_ID no OAuth2 application behind "Continue with Gitea". Redirect URI <PUBLIC_URL>/auth/callback. Written by the first-run setup.
GITEA_OAUTH_CLIENT_SECRET no secret Secret of that OAuth2 application.
GITEA_ADMIN_TOKEN no secret Gitea admin token (write:admin, write:repository, write:issue, write:user, write:organization, read:misc). Creates the Gitea user behind each Anvil account. Without it hosted repositories only work for people who sign in with Gitea. Its name must not start with anvil-.

Sign-in and accounts #

Variable Required Default Secret What it does
GITHUB_CLIENT_ID no OAuth client for "Continue with GitHub" when no GitHub App was created in Settings → GitHub (the App's own client wins). Redirect URI <PUBLIC_URL>/auth/github/callback.
GITHUB_CLIENT_SECRET no secret Secret of that OAuth client.
DASHBOARD_USERS no (empty) Account logins (comma-separated) let in without an invitation.
ADMIN_EMAILS no (empty) Email addresses (comma-separated) whose accounts are admins once they sign in with a verified address. Admin stays on the account.
ADMIN_RECOVERY_EMAIL no (empty) An admin's email address. At start Anvil logs a one-time sign-in link for that admin (valid 15 minutes), for getting back in without mail. Remove it once you're in.
ADMIN_GITHUB_LOGINS no (empty) GitHub logins (comma-separated) that are admins when they sign in with GitHub.

AI #

Variable Required Default Secret What it does
ANTHROPIC_API_KEY yes secret Anthropic API key for reviews, questions, CI diagnosis and agents.
REVIEW_MODEL no claude-opus-5-5 Claude model for reviews and agents.
REVIEW_EFFORT no high Reasoning effort for reviews.
CHAT_EFFORT no medium Reasoning effort for questions in comments and the Ask panel.
REVIEW_ROUTING no auto auto picks a model per review by size and risk (light / standard / deep, see docs/REVIEW-COSTS.md); off sends every review to REVIEW_MODEL.
REVIEW_MODEL_STANDARD no claude-sonnet-5-5 Model for small, low-risk changes (the standard tier).
REVIEW_MODEL_LIGHT no claude-haiku-5-5 Model for docs-only, formatting-only and bot pull requests (the light tier).
CHAT_MODEL no claude-sonnet-5-5 Model for replies to comments and review threads.
REVIEW_MAX_DIFF_CHARS no 160000 Most diff characters sent with the review prompt; the agent reads the rest of the change itself.
MAX_BUDGET_USD no 3 Hard cost ceiling per agent run, in US dollars; .anvil.yaml can lower it, not raise it.
MAX_TURNS no 80 Most agent turns per run.
REVIEW_PACKED_TURNS no 24 Turn limit for deep reviews that start with a context pack; a review that runs out is retried once at MAX_TURNS.
REVIEW_PREP no on on prepares each review without the model first: a context pack of the changed code's callers, callees, types and tests, collapsed renames and moves, static checks, and a review memo (docs/REVIEW-COSTS.md). off reviews the plain diff.
REVIEW_OSV no on on looks up new and changed dependencies in the OSV vulnerability database (network); off only lists them.
SEMGREP_RULES no Semgrep rules to run on changed files before the model (a registry config or a path); unset skips Semgrep.
SEMGREP_BIN no semgrep Path of the semgrep binary, when Semgrep is installed in the image.
REVIEW_CACHE_TTL no 5m Prompt cache lifetime for the stable part of the review prompt: 5m, or 1h (cache writes cost twice as much, reads are reused across reviews of the same repository for longer).
AGENT_TIMEOUT_MS no 1200000 An agent run is stopped after this many milliseconds.
WORK_DIR no /tmp/anvil-work Where checkouts for reviews and agents are made (deleted after each job).
WORKER_CONCURRENCY no 2 Jobs (reviews, agents, CI diagnosis) run at the same time.
AGENT_MEMORY_MB no 1024 Memory one review or agent run is assumed to need; with the container's memory limit it caps how many run at once.
CLAUDE_CODE_PATH no Path to the claude executable, when the bundled one can't be found.
AGENTS_COMMANDS no off local lets code-changing agents run the repository's agents.command (tests, lint) inside the worker. Repository code can then do anything the worker can; off by default.

Mail #

Variable Required Default Secret What it does
SMTP_URL no secret smtps://user:pass@host:465 for invitations and sign-in links. Without it invitation links are shown to copy and email sign-in only works in development.
EMAIL_FROM no Sender of Anvil's emails. Defaults to <INSTANCE_NAME> <noreply@<PUBLIC_URL host>>.
ADMIN_NOTIFY_EMAIL no Where new access requests are announced.

Runners and CI #

Variable Required Default Secret What it does
RUNNERS_SECRET no secret Shared secret between Anvil and the runner manager (runners/manager.mjs). 32+ characters. Without it Anvil runners (runs-on: anvil-*) are off.
RUNNER_MAX_MINUTES_PER_DAY no 600 Runner minutes per repository owner per day.
CI_LOG_RETENTION_DAYS no 30 Days job logs and runner metrics are kept.
CI_LOG_MAX_BYTES no 5242880 The most of one job log that is kept, in bytes.
CI_TEST_RETENTION_DAYS no 90 Days test results are kept.
COMPUTE_RAW_HOURS no 48 Hours raw CPU/memory samples are kept before they are rolled into one-minute averages.
RUNNER_POOL_CPUS no CPU cores of the runner pool shown on the compute pages; by default the pool host protection reports, else the runner host's cores.
RUNNER_POOL_MEMORY_GB no Memory of the runner pool shown on the compute pages, in GB; same fallback as RUNNER_POOL_CPUS.
CI_ESTIMATE_CPUS no 2 CPUs assumed for jobs without samples (Gitea's runner, GitHub-hosted) when estimating compute.
CI_ESTIMATE_MEMORY_GB no 7 Memory assumed for jobs without samples when estimating compute, in GB.
PUBLIC_STATS no on off turns off GET /api/public/compute, the public aggregate CI numbers (counts and totals only, no names).

Git over SSH #

Variable Required Default Secret What it does
GIT_SSH_HOST no Host in SSH clone URLs; defaults to PUBLIC_URL's host. An empty value or off hides SSH in the UI.
GIT_SSH_PORT no 2222 Port of Gitea's SSH server in clone URLs.
GIT_SSH_USER no git User in SSH clone URLs.
GIT_SSH_FINGERPRINTS no (empty) Host key fingerprints shown in the docs, comma-separated, e.g. ED25519 SHA256:…,RSA SHA256:…. Get them with ssh-keyscan -p 2222 <host> | ssh-keygen -lf -.

Development #

Variable Required Default Secret What it does
DEV_LOGIN no Local development only: /auth/login signs in as this user. Ignored when NODE_ENV=production.