Suprnova reads configuration from environment variables (loaded from
.env in development, the process environment in production) and
exposes them to your code in two shapes:
- Direct env access -
env::env,env_required,env_optionalfor one-off lookups - Typed config structs -
Config::register/Config::getfor anything you read more than once, with strong typing
The framework reads a handful of env vars itself (APP_KEY,
APP_ENV, DATABASE_URL, etc.); the rest are yours.
The .env file
suprnova new writes a starter .env with the values your app needs
to boot:
APP_NAME="my-app"
APP_ENV=local # local, development, staging, production, testing, …
APP_DEBUG=true # detailed error pages + verbose logs
APP_URL=http://localhost:8765
# 32-byte AES-256 key (URL-safe base64, no padding). Encrypts session
# cookies, pagination cursors, and anything via `suprnova::Crypt`.
# Generated at scaffold time. Rotate with `suprnova key:generate`.
APP_KEY=<32-byte base64>
SERVER_HOST=127.0.0.1
SERVER_PORT=8765
VITE_PORT=5765
# Database - SQLite by default; swap to postgres://user:pass@host/db
DATABASE_URL=sqlite://./database.db
DB_MAX_CONNECTIONS=10
DB_MIN_CONNECTIONS=1
DB_CONNECT_TIMEOUT=30
DB_LOGGING=false
# Session
SESSION_LIFETIME=120 # minutes
SESSION_COOKIE=suprnova_session
SESSION_SECURE=false # set true in production (HTTPS only)
SESSION_PATH=/
SESSION_SAME_SITE=Lax
# Mail - defaults to `log` driver (writes outgoing mail to the
# tracing log, good for dev). Set MAIL_DRIVER to one of
# smtp / ses / mailgun / postmark / sendgrid / resend / log / memory
# for production.
MAIL_DRIVER=log
# SMTP credentials (only read when MAIL_DRIVER=smtp):
MAIL_SMTP_HOST=127.0.0.1
MAIL_SMTP_PORT=587
MAIL_SMTP_USER=
MAIL_SMTP_PASS=
# starttls | tls | none. Left blank it derives from the credentials
# above - starttls with them, none without. Production refuses to boot
# unencrypted; see the Mail chapter.
MAIL_SMTP_ENCRYPTION=
A sibling .env.example ships the same keys with placeholder values -
commit it; do not commit .env. The default .gitignore excludes
.env already.
How .env loading works
At boot, the framework:
- Detects the environment from
APP_ENV(case-insensitive,prod/dev/stage/stg/testare also recognised). - Loads
.envfrom the project root. - If a per-environment file exists (
.env.staging,.env.production), loads it on top - its values override.env. - Real process environment variables override both (this is what container orchestration relies on).
The order in one line: process env > .env.<environment> > .env.
use Config;
let env = environment; // Environment::Local
let is_prod = is_production; // false
In a CI run with APP_ENV=testing, the framework loads .env.testing
on top of .env so you can override DB URLs and disable mail drivers
without touching the dev .env.
Direct env access
For one-off reads of strings, numbers, bools - anything implementing
std::str::FromStr - use the env::* family:
use ;
let port: u16 = env; // with default
let url: String = env_required; // panics if missing - boot-only
let smtp_host: = env_optional; // None if missing
env(key, default)- type-coerced read with fallbackenv_required(key)- panics if the key is missing or fails to parse. Only use this at boot time (inbootstrap()orconfig::register()) where a missing required value should crash the process immediatelyenv_optional(key)- returnsOption<T>;Nonefor missing or unparseable values
Each unique key is also logged once on first read, so you can audit exactly which env vars your app touches.
Typed config structs
For anything your app reads more than once, define a typed struct and register it. The pattern is:
// src/config/database.rs
use Config;
use ;
Then read it anywhere with one line:
let db = .expect;
println!;
The registry is keyed by TypeId, so each struct is stored once.
Calling Config::register again with the same type replaces the
previous entry - convenient for tests.
Wiring registration into your app
The scaffold's cmd/main.rs includes a .config(…) step in the
fluent boot pipeline:
use Application;
async
my_app::config::register typically delegates to each section module:
// src/config/mod.rs
Deserialising whole structs from env
For larger configs, you can deserialise directly from env vars via
serde. Suprnova exposes two helpers:
use Config;
// Reads SERVER_HOST / SERVER_PORT from the environment
let cfg = ?;
Config::resolve::<T>()- deserialise from all process env varsConfig::resolve_prefixed::<T>("PREFIX_")- deserialise only vars with the given prefix (the prefix is stripped before deserialisation)
Both return Result<T, FrameworkError> so a missing required field
surfaces as a FrameworkError::Internal carrying the envy diagnostic
instead of a panic.
Environment-specific config
The Environment enum covers the standard set:
| Variant | Recognised APP_ENV values |
|---|---|
Local |
local |
Development |
development, dev |
Staging |
staging, stage, stg |
Production |
production, prod |
Testing |
testing, test |
Custom(String) |
anything else (preserves your casing, used for .env.<custom> lookup) |
Common branches:
use ;
if is_production
if is_debug
match environment
is_debug() returns true when APP_DEBUG=true is set explicitly,
or - when APP_DEBUG is unset - when the detected environment is
Local, Development, or Testing. Production, staging, and any
unrecognised custom environment default to false. Keep it off in
production; it controls error-page detail and a few internal defaults.
APP_KEY is required in non-development
In production (any APP_ENV other than local/development/
testing), Suprnova requires APP_KEY to be set to a valid 32-byte
URL-safe base64 string. Booting without it fails closed with a
descriptive error message - there is no silent fallback.
If you don't have an APP_KEY yet:
Neither form edits .env for you - copy the printed key into your
.env (or your secrets manager) yourself.
For key rotation (where old encrypted data must still decrypt during the migration window), see Encryption.
Configuration in tests
In tests, register config in the test setup rather than relying on
.env:
use suprnova_test;
async
The #[suprnova_test] attribute also sets up isolated container
state so concurrent tests don't see each other's bindings - see
Testing.
Common env vars Suprnova reads
A non-exhaustive list - these are vars the framework itself looks at. Your app reads more on top.
| Var | Default | What it does |
|---|---|---|
APP_NAME |
"app" |
Logged at boot, used in some default error messages |
APP_ENV |
local |
Drives Environment::detect and .env.<suffix> lookup |
APP_DEBUG |
env-aware (false in production) |
Verbose error pages + extra logging |
APP_URL |
http://localhost:8765 |
Base URL for absolute URL generation, signed URLs |
APP_KEY |
none (required in prod) | AES-256 key for Crypt, sessions, cursors |
APP_KEY_PREVIOUS |
none | Comma-separated previous keys for rotation (max 8) |
SERVER_HOST |
127.0.0.1 |
Bind address |
SERVER_PORT |
8765 |
Bind port |
DATABASE_URL |
none | Required if your app uses the database |
DB_MAX_CONNECTIONS |
10 |
sqlx pool max |
DB_MIN_CONNECTIONS |
1 |
sqlx pool min |
DB_CONNECT_TIMEOUT |
30 (seconds) |
sqlx pool connect timeout |
SESSION_LIFETIME |
120 (minutes) |
Session expiry |
SESSION_TOUCH_INTERVAL |
300 (seconds) |
Minimum sliding-expiry write cadence |
SESSION_GC_INTERVAL |
3600 (seconds) |
Supervised expired-session cleanup cadence |
SESSION_COOKIE |
suprnova_session |
Cookie name |
SESSION_SECURE |
true |
Set Secure cookie flag. Override to false for local-HTTP development. |
SESSION_SAME_SITE |
Lax |
Strict, Lax, or None |
MAIL_DRIVER |
log |
One of smtp, ses, mailgun, postmark, sendgrid, resend, log, memory |
CACHE_DRIVER |
memory |
One of memory, redis, database |
QUEUE_DRIVER |
memory |
One of memory, redis, database (unknown values warn and fall back to memory) |
RATE_LIMIT_DRIVER |
memory |
One of memory, redis |
LOG_FORMAT |
env-aware (pretty in dev/local, json in production) |
pretty or json |
LOG_LEVEL |
info |
One of error, warn, info, debug, trace |
The full audited list lives in Environment Variables.
Next
- Application Bootstrap - where typed config registration is called from
- Service Container - how registered config is read alongside bound services
- Environment Variables - the full reference list
- Deployment - production env setup
