Environment files
Table of contents
- Introduction
- Which files exist
- How the files are merged
- What the production template carries
- Filling in the required settings
- Optional settings in
deploy/.env - Which file the CLI reads
- Reference
- See also
Introduction
Environment files say how your product runs. They carry database hostnames, ports, credentials, the URLs of feature services and runtime flags. The CLI merges them from your product and its features, one file for development and one for each deployment.
splent product:env --merge --dev
This writes docker/.env, the file your development containers read. You edit the templates, never the generated file.
Never commit
docker/.envordeploy/.env. Only the.exampletemplates go into git.
Which files exist
In your product,
| File | Purpose | In git |
|---|---|---|
docker/.env.dev.example |
The development template | Yes |
docker/.env.prod.example |
The production template, credentials as <SET> |
Yes |
docker/.env |
The development settings, generated | No |
deploy/.env.example |
The merged production template, written by product:build |
Yes |
deploy/.env |
The deployment’s settings, on the host | No |
deploy/.env.base |
The template product:deploy merged last, for the next three-way merge |
No |
In a feature,
| File | Purpose | In git |
|---|---|---|
docker/.env.example |
The feature’s defaults | Yes |
docker/.env.dev.example, docker/.env.prod.example |
Replace .env.example in that environment, as a whole file |
Yes |
docker/.env |
The feature’s settings, generated | No |
Plain settings and their defaults belong in the feature’s pyproject.toml. See Feature settings.
Development reads docker/.env. Production reads deploy/.env, which Compose hands to every container when it starts, so a change takes effect when the container is created again. The production image carries no env file.
How the files are merged
Weakest first, four layers take part.
- A feature’s
docker/.env, or its.env.<env>.examplewhen the.envdoes not exist yet. - A feature’s
[tool.splent.config]. - Your product’s
[tool.splent.config]. - Your product’s own
.env.<env>.example, which always wins.
Between features, the later one wins within each layer. product:env --merge --dev writes docker/.env, and product:build writes deploy/.env.example from each feature’s .env.prod.example (or .env.example). That is how a feature brings REDIS_URL or MAIL_HOST without your product listing them. The port offset and the placeholders are applied on the way.
What the production template carries
The docker/.env.prod.example that product:create scaffolds sets what a deployment behind a TLS proxy needs.
# user-tunable
SPLENT_TRUSTED_PROXIES=1
# GUNICORN_WORKERS=4
# GUNICORN_TIMEOUT=120
# SPLENT_COOKIE_SECURE=true
# MAX_CONTENT_LENGTH=64M
The web port is bound to 127.0.0.1, so only a proxy on the same host reaches the app, and SPLENT_TRUSTED_PROXIES=1 trusts that one proxy. Keep 1 with the nginx feature too, since nginx is the only hop the app talks to. Set 0 when nothing is in front. Never set more than the real number of proxies, or a caller can choose the client address the app sees. See Behind a proxy.
The commented lines are optional. Signing in works over HTTPS and plain HTTP without them, because the cookies follow the request. product:sync-template --docker brings these lines into a product that lacks them.
Filling in the required settings
A setting a template writes as <SET> has no sensible default. product:build fills in the database names (<product>_db, <product>_db_user, <product>_db_test) and leaves every other one empty, marked required.
# required: docker compose up refuses to start until this is set. A long random string will do: openssl rand -hex 32
SECRET_KEY=
# required: docker compose up refuses to start until this is set. A long random string will do: openssl rand -hex 32
MARIADB_PASSWORD=
docker compose up starts nothing while a required key is empty, and the error names the key. Choose the database passwords before the first start, since MariaDB keeps the first ones it gets. product:deploy fills them for you, with random values for the secret key, passwords and secrets.
Optional settings in deploy/.env
These work fine unset. product:build, product:deploy and product:env --merge --prod append each one the file does not set, commented out with its explanation, so whoever edits deploy/.env on the server sees what exists.
# Optional settings. Uncomment a line to use it.
#
# Seconds a worker may spend on one request. Unset means 120.
# GUNICORN_TIMEOUT=120
| Variable | Unset means | Set it when |
|---|---|---|
SPLENT_TRUSTED_PROXIES |
0, no proxy believed |
The app runs behind a reverse proxy |
GUNICORN_WORKERS |
2 x CPUs + 1, by nproc in the container |
The host is shared or small. nproc does not see a --cpus quota |
GUNICORN_TIMEOUT |
120 seconds per request |
A request legitimately takes longer |
SPLENT_COOKIE_SECURE |
auto, Secure when the request came over HTTPS |
Cookies must always be Secure (true) or never (false) |
SPLENT_IMAGE |
The image deploy/docker-compose.yml names |
The host should run another image. See Running a published image |
SPLENT_WEB_PORT, SPLENT_DB_PORT |
The host ports the compose file names, the database on loopback | Other host ports are expected |
MAX_CONTENT_LENGTH |
16 MB, 0 for no limit |
Uploads must be capped at another size |
When your releases publish an image, product:build writes SPLENT_IMAGE as a live # user-tunable line set to the stable image.
An optional line you uncomment is yours, and so is any value you change. product:deploy records the template it merged in deploy/.env.base and merges three ways next time, so your values stay. A # user-tunable key you delete is not added back. See Environment sync strategy.
Which file the CLI reads
shell environment > <product>/deploy/.env (production only) > <product>/docker/.env > workspace .env
An exported variable always wins. While production is deployed (SPLENT_ENV=prod, which product:deploy writes into docker/.env), the CLI loads deploy/.env over docker/.env, so commands such as db:seed use the production values. Edit deploy/.env to change what they see.
WORKING_DIR, SPLENT_APP and SPLENT_HOST_PROJECT_DIR keep the value they had before the product’s files are read.
Reference
Key variables
| Variable | Set by | Used by |
|---|---|---|
SPLENT_APP |
Product | CLI, framework, startup scripts |
SPLENT_ENV |
Developer, CI | CLI (which feature lists apply), startup scripts |
WORKING_DIR |
Docker | CLI, framework (paths) |
MARIADB_HOSTNAME, MARIADB_PORT, MARIADB_DATABASE |
Product env | Framework (database URI, port 3306 when unset), startup scripts |
MARIADB_USER, MARIADB_PASSWORD |
Product env | Framework, health checks, startup scripts |
REDIS_URL, REDIS_HOST_PORT |
A feature that runs Redis | The task queue, app code, Compose |
RUN_DB_SEED |
Product env | 04_handle_migrations.sh, which seeds only an empty database |
SPLENT_MIGRATE_ON_START |
Operator, deploy agent | upgrade (default) migrates at start, check refuses a schema not at head, off does neither. See Startup script integration |
GUNICORN_WORKERS, GUNICORN_TIMEOUT |
Operator | Production entrypoint |
SPLENT_TRUSTED_PROXIES |
Product env (1), operator |
Framework (ProxyFix, HTTPS detection) |
SPLENT_COOKIE_SECURE |
Operator | Framework (Secure cookies) |
SPLENT_IMAGE |
product:build, operator |
The deploy bundle, product:deploy, a feature that deploys the product |
SPLENT_WEB_PORT, SPLENT_DB_PORT |
Operator | The deploy bundle (host ports) |
SPLENT_WEB_BIND_HOST, SPLENT_DB_BIND_HOST |
Product env (127.0.0.1), operator |
Compose (the interface each port is published on) |
MAX_CONTENT_LENGTH |
Operator | Framework (largest request body) |
SELENIUM_GRID_URL, SELENIUM_BROWSER, SELENIUM_TARGET_URL |
Developer, CI | The E2E driver |
SPLENT_LOCUSTFILES |
Developer, CI | The Locust bootstrap |
Who reads them
| Reader | Reads |
|---|---|
product:env |
The .env.example templates, to generate and merge .env files |
product:build |
The .env.prod.example of the product and its features, to write deploy/.env.example |
product:deploy |
deploy/.env.example, to write or merge deploy/.env |
| Docker Compose | The env file it is given, deploy/.env for the bundle |
| Startup scripts and health checks | $MARIADB_*, $RUN_DB_SEED |
See also
- Feature settings, where a feature declares its defaults
product:env,product:buildandproduct:deploy