Configuration Reference
The engine is configured with environment variables. This page lists the engine's variables, grouped by what you are setting up, with the default the engine applies. Each feature page lists the settings of its own feature, and Feature settings says where each one is.
Start here
Section titled “Start here”Seven variables decide whether the engine starts. Set these first.
| Variable | What it does | Default |
|---|---|---|
DATABASE_URL | Connection string. The scheme picks the database: postgres:// or postgresql://, mysql://, or sqlserver://. See supported databases. | required |
JWT_SECRET | Fallback token signing secret, at least 16 characters. Sessions are signed with an Ed25519 key the engine creates at JWT_KEY_PATH, but the engine refuses to start without this value. | required |
ENCRYPTION_KEY | Encrypts stored credentials with AES-256-GCM. At least 32 characters and different from JWT_SECRET. A new value makes the stored credentials unreadable, so generate it once. | required |
APP_ENV | production or development. Production refuses a weak configuration, as listed below. | production |
LYEVE_AUDIT_HMAC_KEY | Key for the audit log's tamper-evident chain. Exactly 64 hex characters. | required in production |
RATE_LIMIT_RPS | Requests per second per client address for the global limiter. Unset or 0 turns the limiter off, which production refuses. | unset |
SECURE_COOKIE | true marks cookies Secure, sends HSTS and redirects plain HTTP to HTTPS. Production refuses any other value. | false |
A minimal production environment, with each secret generated separately:
DATABASE_URL="postgres://lyeve:<password>@db.example.com:5432/lyeve?sslmode=require"JWT_SECRET="$(openssl rand -hex 32)"ENCRYPTION_KEY="$(openssl rand -hex 32)"LYEVE_AUDIT_HMAC_KEY="$(openssl rand -hex 32)"RATE_LIMIT_RPS=100SECURE_COOKIE=trueLYEVE_CONSOLE_URL="https://admin.example.com"For a local try, set APP_ENV=development and the production checks are skipped. A
stateless engine needs neither DATABASE_URL, JWT_SECRET nor
ENCRYPTION_KEY.
What production refuses
Section titled “What production refuses”With APP_ENV unset or production, the engine does not start when:
SECURE_COOKIEis nottrue.RATE_LIMIT_RPSis unset or0.LYEVE_AUDIT_HMAC_KEYis unset or is not exactly 64 characters.JWT_EXPIRY_SECSis above3600.DATABASE_URLorDATABASE_REPLICA_URLsigns in as the database's default superuser:postgreson PostgreSQL,rooton MySQL,saon SQL Server.- The signing key file at
JWT_KEY_PATHis readable by group or others, or cannot be created. LYEVE_CONSOLE_URLis set and does not start withhttps://.
In every environment, the engine does not start when:
ENCRYPTION_KEYis unset. The engine then usesJWT_SECRETin its place, and the two may not be equal.JWT_SECRETis shorter than 16 characters, orENCRYPTION_KEYshorter than 32, or the two are equal.- Either secret is a placeholder:
secret,passwordordefault, or a value containingchangeme,change-me,change-this,replace-me,replaceme,your-secret,dev-secret,insecure,exampleorplaceholder. CORS_ORIGINScontains*.JWT_ALG,PASSWORD_HASH_ALGO,STORAGE_DRIVERorDATABASE_DRIVERnames a value the engine does not support.- One of the engine's numbers or durations does not parse. A few, such as the
POOL_*andHEALTH_*values, fall back to their default instead.
A production engine starts but logs a warning on every boot when LYEVE_CONSOLE_URL is unset,
and when a PostgreSQL DATABASE_URL sets no sslmode or one other than require,
verify-ca or verify-full.
Where settings come from
Section titled “Where settings come from”The engine reads each setting from four places. The highest one that has it wins:
- An environment variable. A variable set to an empty value turns the setting off, and no lower layer fills it back in.
- The YAML file,
lyeve.yaml. It wins over the admin console unless the value is tagged!overridable. - The admin console, which holds what a feature's configuration form saved.
- The built-in default.
The engine reads the variables in the engine tables on this page once, at startup, before it connects to the database. Set them in the environment or the file, and restart to change them. A feature's settings, such as the mail relay or the idempotency TTLs, can also be saved in the console. A setting the feature reads each time it uses it applies at once. One it reads only when it starts applies at the next restart. Three are kept until a restart on purpose, because changing them under a running server breaks something that cannot be undone:
- the WebAuthn relying party (every registered passkey stops working)
- the encryption key (stored credentials become unreadable)
- the idempotency keyspace and backend (a retry stops finding its record, so the request runs twice)
GET /api/admin/config (super admin) lists every setting that the environment, the file or the
console sets, with the layer it came from and, for an engine setting, what it does and its
default. Secrets show no value. PUT /api/admin/config (super admin) saves into
the console layer and refuses a key a higher layer holds:
curl -X PUT https://admin.example.com/api/admin/config \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"values": {"flow_run_retention": "168h"}}'The answer lists what it stored under saved, each with the layer it now resolves from, and
what it refused under refused, each with the reason and, for a file value, the file and line. When nothing
could be saved it answers 409. The quickstart shows how
to get TOKEN.
The YAML file
Section titled “The YAML file”Every variable that is not marked "environment only" below has a place in lyeve.yaml. A
nested key is the variable name with the path joined by underscores, so storage.s3.bucket is
STORAGE_S3_BUCKET:
database: url: ${DATABASE_URL} max_connections: 25storage: driver: s3 s3: bucket: media region: eu-west-1Flat names work too, so an existing .env file can be copied in a line at a time. ${VAR} and
${VAR:-fallback} read the process environment, which is how a container passes a secret in
without it living in a committed file.
The engine looks for lyeve.yaml or lyeve.yml in the working directory, then in
/etc/lyeve/, then for a /etc/lyeve/conf.d/ directory. LYEVE_CONFIG points at a specific
file or directory instead. A named path that does not exist stops the boot.
Feature settings in the file
Section titled “Feature settings in the file”Feature settings go under a plugins block, which drops its own segment, because a feature's
key already names it. plugins.cache.driver is CACHE_DRIVER:
plugins: cache: driver: !overridable redis ttl: "60s"!overridable lets the admin console take a key over. Without it the file value is final, and
the console shows the field read-only, naming the file and line it came from.
LYEVE_OVERRIDABLE does the same for environment variables: a comma-separated list of keys the
console may take over. A listed key keeps its variable's value until something is saved against
it. It is read once at startup.
Composing files
Section titled “Composing files”$include: - base.yaml - environments/staging.yaml - schemas/*.yamlIncluded files merge first, so the including file overrides them. A conf.d/ directory beside
the named file merges last, which lets a deployment extend a packaged base without editing it.
A directory of files merges in lexical order, so 10-base.yaml then 20-staging.yaml layers
the way it reads. Content types can be declared in these files too. See
Moving content types between projects.
Credentials saved in the console
Section titled “Credentials saved in the console”A credential saved on a feature's configuration form is encrypted at rest with a key derived
from ENCRYPTION_KEY and is never returned. A set credential reads as ********. Writing that
value back leaves the stored one alone, so editing one field of a form does not overwrite the
rest. Submitting an empty value clears it.
Database
Section titled “Database”| Variable | What it does | Default |
|---|---|---|
DATABASE_URL | See Start here. | required |
DATABASE_MAX_CONNECTIONS | Most connections the engine opens to the database. Multiply by the number of replicas and stay under the database's own limit. | 25 |
DATABASE_REPLICA_URL | A read replica. Read-heavy queries that tolerate lag go to it. Production refuses a default superuser here too. | unset (all reads go to the primary) |
DATABASE_REPLICA_MAX_CONNS | Most connections to the replica. | 30 |
Pool tuning and an external pooler
| Variable | What it does | Default |
|---|---|---|
DB_POOL_MIN_CONNS | Connections opened at startup, so the first requests do not wait for a handshake. | 2 |
DB_CONN_MAX_LIFETIME | How long a connection is used before it is replaced, as a duration. | 1h |
DB_POOL_HEALTH_CHECK_PERIOD | How long an idle connection stays open before it is closed. Above zero, it replaces DB_CONN_MAX_IDLE_TIME. | 30s |
DB_CONN_MAX_IDLE_TIME | The idle timeout used when DB_POOL_HEALTH_CHECK_PERIOD is 0. | 5m |
MIGRATIONS_PATH | Directory of the database migrations the engine applies at startup. The image sets it. | ./migrations (/app/migrations in the image) |
DATABASE_DRIVER | Overrides the database type read from DATABASE_URL: postgres, mysql or mssql. Leave it unset. | read from the URL |
CONNECTION_POOLER | pgbouncer or proxysql when an external pooler sits in front of the database, so the pool health report at GET /api/admin/pool/health includes its sizing. The engine does not configure the pooler. | none |
POOL_MAX_CLIENT_CONN | The pooler's client connection limit, for that report. Environment only. | 100 |
POOL_DEFAULT_POOL_SIZE | The pooler's default pool size, for that report. Environment only. | 20 |
POOL_RESERVE_POOL_SIZE | The pooler's reserve pool size, for that report. Environment only. | 5 |
POOL_TENANT_SIZES | Per-tenant pool sizes as a JSON array of {"slug", "pool_size", "min_pool_size", "max_connections", "db_name"}. Invalid JSON is logged and ignored. Environment only. | unset |
POOL_HEALTH_MAX_LATENCY | Ping latency above which the pool health report says degraded. Environment only. | 1s |
POOL_HEALTH_MIN_IDLE | Idle connections below which the report says degraded. Environment only. | 1 |
POOL_HEALTH_MAX_UTIL | Share of the pool in use above which the report says degraded. Environment only. | 0.9 |
The CONNECTION_POOLER and POOL_* sizing variables are read only when CONNECTION_POOLER
names a pooler. The POOL_HEALTH_* thresholds are read on every install.
Network and proxies
Section titled “Network and proxies”| Variable | What it does | Default |
|---|---|---|
LYEVE_CONSOLE_URL | The admin console's public URL, such as https://admin.example.com. Password reset and magic-link emails link to pages the console serves, and device sign-in shows its approval page there. It must be an absolute URL with no query or fragment. In production it must be https, and while it is unset password reset and magic-link sign-in refuse to start and device sign-in answers 503. | http://localhost:5173 outside production |
LYEVE_BASE_URL | The public base URL of the engine. Features that build an absolute link to it use this value instead of the request's Host header: OAuth and SAML callback URLs, data export downloads and file links. Set it in production. | unset |
TRUSTED_PROXIES | Comma-separated CIDRs of the reverse proxies in front. X-Forwarded-For is honored only from these, so rate limits and audit entries see the real client address. Unset, every request counts as the proxy's. | unset |
CORS_ORIGINS | Comma-separated origins of the browser apps that call the APIs cross-origin. * is refused. | http://localhost:5173 |
ADMIN_LISTEN_ADDR | Bind address of the Admin API. | 0.0.0.0:3001 |
API_LISTEN_ADDR | Bind address of the Content API. | 0.0.0.0:3002 |
TLS_CERT_FILE, TLS_KEY_FILE | A PEM certificate and key, set together. Both listeners then serve TLS 1.2 or later and pick up a rotated certificate without a restart. Unset, both serve plain HTTP for a proxy that terminates TLS. | unset |
Host and address filters, CORS details
| Variable | What it does | Default |
|---|---|---|
ALLOWED_HOSTS | Comma-separated host names the engine answers to. Any other Host header gets 421. | unset (every host) |
IP_ALLOWLIST | Comma-separated CIDRs or addresses allowed to connect. Others get 403. An entry that does not parse stops the boot. | unset (every address) |
CORS_ALLOWED_DOMAINS | Comma-separated domain suffixes under which a tenant's own domain may call the APIs cross-origin, such as example.com for shop.example.com. Empty allows no tenant domain. | unset |
CORS_ALLOW_METHODS | Methods the preflight allows. | GET, POST, PUT, DELETE, PATCH, OPTIONS |
CORS_ALLOW_HEADERS | Request headers a browser may send. It replaces the default list, so keep Authorization and X-Tenant-ID if you set it. | Content-Type, Authorization, X-API-Key, X-Tenant-ID, X-Correlation-ID, X-CSRF-Token |
CORS_EXPOSE_HEADERS | Response headers a cross-origin script may read. The default lets a browser client read the request id and the rate-limit values. | X-Request-Id, X-Correlation-ID, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After |
CORS_MAX_AGE | Seconds a browser may cache the preflight. | 3600 |
Sign-in, tokens and passwords
Section titled “Sign-in, tokens and passwords”| Variable | What it does | Default |
|---|---|---|
JWT_KEY_PATH | Where the Ed25519 signing key is kept. Put it on a volume, or give every replica the same file, or each restart signs everyone out. In production the file must be readable by its owner only. | /var/lib/lyeve/jwt_key.json |
JWT_EXPIRY_SECS | Session token lifetime in seconds. Production refuses a value above 3600. | 900 (15 minutes) |
REFRESH_TOKEN_TTL_SECS | Refresh token lifetime in seconds. | 2592000 (30 days) |
LYEVE_SETUP_TOKEN | The token the first-run setup asks for, at least 16 characters. Unset, the engine prints a one-time token to its log while no account exists. Set it when more than one replica can answer setup, since each prints its own. | unset (a logged one-time token) |
ADMIN_CONSOLE_KEY | A secret of at least 32 characters, shared with the admin console. The console signs its calls with the browser's address, so sign-in limits count each person instead of the console server. | unset |
PASSWORD_MIN_LENGTH | Shortest password accepted. | 12 |
Signing, rotation, password rules and setup mode
| Variable | What it does | Default |
|---|---|---|
JWT_ALG | EdDSA signs sessions with the Ed25519 key. HS256 signs them with JWT_SECRET and creates no key file. Any other value stops the boot. Environment only: a value in the file passes the check but does not change the signing. | EdDSA |
JWT_SECRETS | Comma-separated HS256 secrets that verify tokens during a rotation. JWT_SECRET still signs, so list its value first and the old secret after it. Unset, JWT_SECRET alone verifies. | unset |
ADMIN_CONSOLE_KEY_PREVIOUS | The old console key, still accepted while you rotate. Set the new key in ADMIN_CONSOLE_KEY, move the console to it, then unset this one. Needs ADMIN_CONSOLE_KEY, at least 32 characters. | unset |
PASSWORD_HASH_ALGO | bcrypt or argon2id. | bcrypt |
PASSWORD_REQUIRE_COMPLEXITY | Requires an upper-case letter, a lower-case letter and a digit. | true |
PASSWORD_CHECK_COMMON | Refuses passwords on a list of common ones. | true |
TRUSTED_ISSUERS | Comma-separated base URLs of outside OpenID Connect issuers whose tokens the Content API accepts. Keys are fetched from {issuer}/.well-known/jwks.json. See Scaling. | unset |
TRUSTED_ISSUER_POLICIES | A JSON array giving each trusted issuer its tenant and the roles its users map to. An issuer with no policy has its tokens ignored, and a policy for an unlisted issuer stops the boot. | unset |
API_KEY_PEPPER | A server secret mixed into every stored API key hash. See API keys. | unset |
ENFORCE_API_KEY_PEPPER | true stops the boot when no API_KEY_PEPPER is found. | false |
LYEVE_SETUP_MODE | true lets the engine start without DATABASE_URL, JWT_SECRET or ENCRYPTION_KEY. It then serves only the probes and the setup routes, and the admin console shows what to set. See Installation. | unset |
Request limits
Section titled “Request limits”| Variable | What it does | Default |
|---|---|---|
RATE_LIMIT_RPS | See Start here. | unset |
RATE_LIMIT_BURST | Requests a client address may send at once above the steady rate. | twice RATE_LIMIT_RPS, at least 1 |
MAX_BODY_BYTES | Largest request body on any route, in bytes. Sized for uploads. | 10485760 (10 MiB) |
MAX_JSON_BODY_BYTES | Largest body on JSON routes. Only Content-Length is checked, so a chunked request without it meets MAX_BODY_BYTES instead. | 1048576 (1 MiB) |
Per-tenant limits, public routes and load shedding
| Variable | What it does | Default |
|---|---|---|
RATE_LIMIT_PER_TENANT | true counts the global limit per tenant and address instead of per address. | false |
PUBLIC_RATE_LIMITS | Per-route caps for public routes, comma-separated METHOD:/pattern=rate:burst entries using the route pattern exactly as documented, such as POST:/api/v1/flows/hooks/{flow_id}=20:40. Entries merge over the built-in table, so a route you do not name keeps its own limit. A malformed entry stops the boot and names the entry. | built-in table |
PUBLIC_RATE_LIMIT_GLOBAL | Combined per-address cap across every public route, as rate:burst. Raise it where many callers share one address: a CDN, a proxy on loopback, a load generator. | 50:100 |
BACKPRESSURE_ENABLED | Turns load shedding on. See Scaling. | false |
BACKPRESSURE_MAX_INFLIGHT | Requests in flight before the engine sheds load. | 200 |
BACKPRESSURE_TENANT_QUOTA_PCT | Share of that budget one tenant may hold, above 0 and at most 1. | 0.4 |
BACKPRESSURE_POOL_PRESSURE_THRESHOLD | Share of the database pool in use at which shedding begins, above 0 and at most 1. | 0.85 |
To share the per-address limit across replicas through Redis, set RATE_LIMIT_BACKEND=redis.
That setting belongs to Rate limiting.
Storage
Section titled “Storage”These settings drive the engine's own file store. The Object storage
feature runs on every install by default and takes its place. While it runs, STORAGE_DRIVER
changes nothing, and the STORAGE_S3_* values only create its first provider on a start that
finds none.
| Variable | What it does | Default |
|---|---|---|
STORAGE_DRIVER | Where uploaded files go: local or s3. | local |
STORAGE_LOCAL_PATH | Directory for the local driver. Mount a volume here. | ./uploads (/app/uploads in the image) |
STORAGE_BASE_URL | Public base URL of files kept by the local driver. | unset |
S3-compatible bucket
| Variable | What it does | Default |
|---|---|---|
STORAGE_S3_BUCKET | Bucket name. | unset |
STORAGE_S3_REGION | Bucket region. | us-east-1 |
STORAGE_S3_ENDPOINT | Endpoint of an S3-compatible service such as R2 or MinIO. Unset uses AWS. | unset |
STORAGE_S3_KEY | Access key id. | unset |
STORAGE_S3_SECRET | Secret access key. | unset |
STORAGE_S3_CDN_BASE_URL | Public base URL that file links use, such as a CDN in front of the bucket. | unset |
STORAGE_S3_USE_SSL | Connects to the endpoint over TLS. | true |
STORAGE_S3_FORCE_PATH_STYLE | true addresses the bucket in the path, as MinIO needs. | false |
STORAGE_S3_MULTIPART_MB | Size in MB above which an upload is sent in parts. | 5 |
Object storage covers buckets per provider and signed links.
The mail relay is read by the features that send mail: Email, Password reset and Magic link sign-in. It can also be saved on the email feature's configuration form, and a variable set in the deployment still wins.
| Variable | What it does | Default |
|---|---|---|
SMTP_HOST | SMTP server host name. Unset, no mail is sent. | unset |
SMTP_PORT | SMTP server port. | 587 |
SMTP_USER | SMTP user name. | unset |
SMTP_PASS | SMTP password. | unset |
SMTP_FROM | The From address of outbound mail. | unset |
SMTP_TLS | Exactly true selects implicit TLS, usually on port 465. Any other value sends over STARTTLS. Read by the Email feature only. | false |
Caching and Redis
Section titled “Caching and Redis”| Variable | What it does | Default |
|---|---|---|
CACHE_TTL | How long the Content API keeps an entry or a list in its memory cache, as a duration. The Caching feature uses it as its default TTL. | 60s |
CACHE_MAX_ENTRIES | Most entries in each of those memory caches. | 1000 |
CACHE_DRIVER | The Caching feature's backend: memory or redis. Set redis to share sessions and sign-in lockouts across replicas. The Content API caches stay in memory either way. | memory |
REDIS_URL | The Redis that caching, idempotency, shared rate limits, realtime and flows use, unless a feature names its own. | redis://localhost:6379/0 |
Scaling lists what more than one replica needs from Redis.
Idempotency
Section titled “Idempotency”An Idempotency-Key header on a write makes it safe to retry: the request runs once, and a
retry with the same key gets the stored answer. Keys are kept per tenant and user. Included free.
See Idempotent requests.
| Variable | What it does | Default |
|---|---|---|
REDIS_URL | Shares idempotency records between replicas, so a retry that lands on another replica still finds its record. A Redis on the local host that does not answer falls back to in-process records and logs why. A remote one that does not answer stops the feature from starting. | redis://localhost:6379/0 |
IDEMPOTENCY_KEYSPACE | Prefix on every stored key. Needs a restart to change, as does the backend. The settings below apply without one. | idem |
IDEMPOTENCY_LOCK_TTL | How long a request in flight holds its key. A handler that outlives its lock is logged. | 30s |
IDEMPOTENCY_DATA_TTL | How long a finished answer is kept for replay. | 24h |
IDEMPOTENCY_AUTO_GENERATE | Derives a key from the tenant, user, method, path and body when a request has none. | false |
IDEMPOTENCY_AUTO_METHODS | Comma-separated methods that get a derived key. | POST |
License, features and mode
Section titled “License, features and mode”| Variable | What it does | Default |
|---|---|---|
LYEVE_LICENSE_KEY | A signed license token, verified offline, or a license key, which the engine exchanges once for a token. Free features run with or without it. | unset (free features only) |
LYEVE_PLUGINS | Comma-separated features to start. Empty starts every feature that is free or your license covers. See Licensing and tiers. | empty |
LYEVE_LICENSE_SERVER_URL | Where a license key is exchanged. https only. Never contacted when LYEVE_LICENSE_KEY holds a token. | https://api.lyeve.com |
LYEVE_LICENSE_CACHE_DIR | Where the verified token and the install id are cached. | /var/lib/lyeve |
MULTI_TENANT | true serves more than one tenant from one install. See Tenants. | false |
LYEVE_MODE | stateless runs the engine with no database. Any other value stops the boot. See Stateless mode. | unset |
LYEVE_CONFIG | Path of the YAML file or directory to read. Environment only. | unset (the search above) |
LYEVE_OVERRIDABLE | Comma-separated variables the admin console may take over. Environment only. | unset |
Health checks and shutdown
Section titled “Health checks and shutdown”/healthz, /readyz and /startup answer on both listeners. See
health endpoints for what each one checks.
| Variable | What it does | Default |
|---|---|---|
PRESTOP_DRAIN_SECS | Seconds /readyz answers 503 before shutdown starts, so the load balancer stops sending traffic first. | 5 |
GRACEFUL_SHUTDOWN_SECS | Seconds requests in flight get to finish. | 60 |
Readiness thresholds
| Variable | What it does | Default |
|---|---|---|
HEALTH_DISK_PATH | Directory whose free space /readyz checks. Environment only. | STORAGE_LOCAL_PATH |
HEALTH_DISK_MIN_MB | Free space in MB below which /readyz answers 503. Environment only. | 100 |
HEALTH_REDIS_PROBE_REQUIRED | true makes /readyz answer 503 when the Redis that holds sessions is unreachable. Unset, that outage is reported but the replica stays in service. Environment only. | false |
HEALTH_GOROUTINE_MAX | Goroutine count above which /readyz reports a warning. It does not fail the check. Environment only. | 10000 |
POOL_EXHAUSTION_THRESHOLD | Share of the database pool in use above which /readyz reports a warning. It does not fail the check. Environment only. | 0.8 |
Observability
Section titled “Observability”| Variable | What it does | Default |
|---|---|---|
METRICS_TOKEN | Bearer token for GET /api/admin/metrics, so a scraper needs no admin account. While it is set, any other bearer token on that route answers 401. Unset, the endpoint answers a super admin. | unset |
OTEL_EXPORTER_OTLP_ENDPOINT | OpenTelemetry collector to send traces to. Unset, tracing is off. | unset |
INSTANCE_ID | Names this replica in logs, traces and the replica list. | host name and process id |
Tracing, debug traces and compression
| Variable | What it does | Default |
|---|---|---|
OTEL_EXPORTER_OTLP_INSECURE | true sends to the collector without TLS. | false |
TRACING_SAMPLING_RATE | Share of traces kept, 0.0 to 1.0. A value outside that range stops the boot. | 1.0 |
TRACING_TENANT_SAMPLING_RATES | Per-tenant rates as comma-separated tenant=rate pairs. A malformed pair stops the boot. | unset |
LYEVE_DEBUG_TRACER_ENABLED | true lets an admin send X-Debug: true and get a trace of the request instead of the normal answer. | false |
COMPRESS_GZIP_JSON_LEVEL | gzip level for JSON responses. Environment only. | 4 |
COMPRESS_BROTLI_JSON_LEVEL | Brotli level for JSON responses. Environment only. | 2 |
COMPRESS_GZIP_TEXT_LEVEL | gzip level for text and HTML responses. Environment only. | 6 |
COMPRESS_BROTLI_TEXT_LEVEL | Brotli level for text and HTML responses. Environment only. | 4 |
Privacy and regions
Section titled “Privacy and regions”| Variable | What it does | Default |
|---|---|---|
LYEVE_GDPR_HOLD_CHECK | What an erasure request does when a legal-hold check is set up but cannot answer. refuse answers 503 and erases nothing. proceed erases anyway. Environment only. | refuse |
INSTANCE_REGION | The data region this install serves. Answers carry it in X-CMS-Region, and Data residency compares a tenant's region against it. | unset |
An active legal hold stops POST /api/admin/gdpr/erase from erasing the person it covers. The
request succeeds with total_rows: 0 and names the holds. Holds need the audit-retention
feature. See Data protection.
Concurrency and resources
Section titled “Concurrency and resources”The engine sizes itself to the container's memory and CPU limits, which it reads from the
cgroup. GOMEMLIMIT and GOMAXPROCS, Go's own variables, win when you set them.
Memory, CPU and worker pools
| Variable | What it does | Default |
|---|---|---|
MEMORY_LIMIT_BYTES | Memory limit used when the cgroup sets none. The engine sets Go's soft memory limit to 85% of the limit it finds. | from the cgroup |
CPU_QUOTA | Whole cores the engine schedules for, instead of the cgroup's CPU limit. | from the cgroup |
GOROUTINE_ENGINE_ENABLED | Warms and stops features in parallel, applies GOROUTINE_ENGINE_POOL_SIZE and allows asynchronous hooks. The shared worker pool runs either way. See Concurrency tuning. | false |
GOROUTINE_ENGINE_POOL_SIZE | Workers in the shared pool. Applied only with GOROUTINE_ENGINE_ENABLED=true. | 100 |
DB_WARMUP_PARALLELISM | How many tasks the parallel stages, such as cache warmup, run at once. | 4 |
ASYNC_HOOKS_ENABLED | Runs after-save hooks in the background instead of inside the request. Needs GOROUTINE_ENGINE_ENABLED=true. | false |
ASYNC_HOOK_TIMEOUT | How long one asynchronous hook may run. | 5s |
CONTROL_STRICT_MODE | true stops the boot when a security control reports that it is not enforced. Unset, the engine logs the report and starts. Environment only. | false |
Feature settings
Section titled “Feature settings”Each feature lists its own settings on its page. Find a variable here by its prefix.
| You are setting up | Variables | Page |
|---|---|---|
| Shared caching | CACHE_*, REDIS_URL | Caching |
| Rate limits across replicas | RATE_LIMIT_BACKEND, RATE_LIMIT_REDIS_URL | Rate limiting |
| Uploads and images | MEDIA_* | Media |
| Signed upload and download links | MAX_PRESIGN_*, STORAGE_LOCAL_SIGNING_SECRET | Object storage |
| Keeping a tenant's files in its region without a data residency assignment | STORAGE_TENANT_REGIONS | Object storage |
| Search | SEARCH_* | Search |
| Outbound mail | SMTP_* | |
| Magic links | MAGIC_LINK_* | Magic link sign-in |
| Passkeys and one-time codes | WEBAUTHN_*, MFA_TOTP_ISSUER | Multi-factor authentication |
| Bot checks | CAPTCHA_* | Captcha |
| Device and IP reputation | DEVICE_FINGERPRINT_CONFIG, IPREP_* | Trusted devices |
| GraphQL | GRAPHQL_* | GraphQL API |
| gRPC | GRPC_* | gRPC API |
| Realtime | REALTIME_* | Realtime |
| Message brokers | EVENT_BUS, NATS_*, KAFKA_*, RABBITMQ_* | Message broker events |
| Outbound webhooks | WEBHOOK_ALLOWED_PRIVATE_NETWORKS | Webhooks |
| Flows | FLOW_RUN_RETENTION, FLOW_CRON_ENABLED | Flows |
| Metrics export | METRICS_* other than METRICS_TOKEN | Metrics export |
| Error alerts | ERROR_TRACKING_*, SLACK_WEBHOOK_URL, DISCORD_WEBHOOK_URL | Error tracking |
| Analytics | ANALYTICS_* | Analytics |
| Uptime probes | SYNTHETIC_MONITORING_* | Synthetic monitoring |
| Request profiling | PROFILER_* | Request profiling |
| Slow queries | QUERY_MONITOR_* | Slow query analysis |
| Data exports | DATA_EXPORT_* | Data export |
| Tenant backups and keys | KMS_*, STORAGE_S3_BACKUP_ALLOWED_BUCKETS, REPLICATION_TARGETS | Tenants |
| AI | AI_* | AI |
Related
Section titled “Related”- Production checklist: every setting to confirm before go-live, one line each.
- Secure your instance: the hardening steps behind these settings.
- Scaling: what more than one replica needs.
- Choose where to run LyEve: hosts and databases.