Configuration & ENV_CONFIG

Lila uses a .env file as the single source of truth for all application settings. Framework variables like DEBUG, PORT, and SECRET_KEY are loaded automatically with proper type casting (string, integer, boolean). For any custom variable you add to .env, the ENV_CONFIG proxy gives you instant access from anywhere in your project — no extra registration needed.

The .env File

After running lila-init, your project includes a .env file with all framework defaults. To change any setting, just edit this file — no code changes are needed.

.env

# ─── Server ────────────────────────────────────────────
# SECRET_KEY is mandatory: an empty/placeholder value makes Lila
# generate a persistent .lila_secret (0600) and warn.
SECRET_KEY="replace-with-a-long-random-string"
DEBUG=True
PORT=8000
HOST=127.0.0.1
WORKERS="1"

# ─── Application URL ──────────────────────────────────
# Production URL for sitemaps, robots.txt, canonical links and secure cookies.
# Leave empty in development — uses http://HOST:PORT automatically.
APP_URL=""

# ─── Project Metadata ─────────────────────────────────
TITLE_PROJECT="Lila Application"
VERSION_PROJECT="2.0.0"
DESCRIPTION_PROJECT="Full-stack lightweight Python application"
LANG_DEFAULT="es"

# ─── SEO Defaults ─────────────────────────────────────
DESCRIPTION_DEFAULT="Lila Framework 2.0 Web App"
KEYWORDS_DEFAULT="python, lila, spa, fast"
AUTHOR_DEFAULT="Lila Developer"

# ─── Cache ────────────────────────────────────────────
CACHE_DRIVER="memory"          # memory | redis | file
CACHE_DIR="app/cache/data"
CACHE_MAX_ITEMS=10000
CACHE_DEFAULT_TTL=300
MODEL_CACHE_TTL=5

# ─── Your Custom Variables ─────────────────────────────
# Add any variable here and access it via ENV_CONFIG
STRIPE_API_KEY="sk_test_..."
                    

Built-in Framework Variables

These variables are recognized by the framework automatically. They are type-casted (string → int, bool, etc.) and available as module-level constants via from app.config import ...

Variable Type Default Description
SECRET_KEY str "" Signs sessions and CSRF tokens. Empty/placeholder → generated once and stored in .lila_secret (0600).
PORT int 8000 Server port
HOST str "127.0.0.1" Server host address
APP_URL str "" Production URL (sitemaps, robots.txt, canonical links, secure cookies). Falls back to http://HOST:PORT when empty.
DEBUG bool False Debug mode (reload, dev SSE, /debug when debug_html=True). Scaffolds set it to True in development.
WORKERS str "1" Number of Uvicorn workers (used by the scaffolded main.py / lila run -w)
TITLE_PROJECT str "Lila Application" Project title (templates, OpenAPI, desktop window)
VERSION_PROJECT str "2.0" Project version (OpenAPI info)
DESCRIPTION_PROJECT str "Full-stack lightweight Python application" Project description for OpenAPI docs
LANG_DEFAULT str "es" Default language for i18n (lila init asks for it)
DESCRIPTION_DEFAULT str "Lila Framework 2.0 Web App" Default meta description for SEO
KEYWORDS_DEFAULT str "python, lila, spa, fast" Default meta keywords for SEO
AUTHOR_DEFAULT str "Lila Developer" Default author for meta tags
CACHE_DRIVER str "memory" memory, redis (only if reachable) or file
CACHE_DIR / CACHE_MAX_ITEMS / CACHE_DEFAULT_TTL str / int / int app/cache/data / 10000 / 300 File-cache directory, LRU capacity and default TTL
MODEL_CACHE_TTL int 5 Seconds a model read stays in the single-flight cache

Using Framework Variables

There are two ways to read configuration:

Importing framework variables

from app.config import DEBUG, HOST, PORT, SECRET_KEY

if DEBUG:
    print(f"Running in debug mode on {HOST}:{PORT}")

# Or read typed values from the framework proxy
from lila.core.config import ENV_CONFIG, is_debug, get_secret_key

debug = is_debug()                       # bool, never bool("False")
max_items = ENV_CONFIG.get_int("CACHE_MAX_ITEMS", 10000)
origins = ENV_CONFIG.get_list("CORS_ORIGINS", [])
                    

ENV_CONFIG — Access Any .env Variable

ENV_CONFIG is a dict-like proxy that gives you instant access to any variable defined in your .env file — including custom ones that are not part of the framework. No registration, no configuration — just add the variable to .env and read it.

Using ENV_CONFIG

from app.config import ENV_CONFIG

# Access with [] — raises KeyError if not found
stripe_key = ENV_CONFIG["STRIPE_API_KEY"]

# Access with .get() — returns a default if not found
redis_url = ENV_CONFIG.get("REDIS_URL", "redis://localhost:6379")

# Check if a variable exists
if "CUSTOM_FEATURE_FLAG" in ENV_CONFIG:
    print("Feature flag is set!")

# Works with any variable in .env — no registration needed
api_version = ENV_CONFIG.get("API_VERSION", "v1")
                    

Real-World Example

A common pattern is combining framework variables with custom ENV_CONFIG variables in your routes and services:

app/routes/api.py

from lila.core.routing import Router
from lila.core.request import Request
from lila.core.responses import JSONResponse
from app.config import DEBUG, ENV_CONFIG

router = Router("api")

@router.get("/status")
async def status(request: Request):
    return JSONResponse({
        "debug": DEBUG,
        "api_version": ENV_CONFIG.get("API_VERSION", "v1"),
        "feature_x": ENV_CONFIG.get("ENABLE_FEATURE_X", "false"),
    })

@router.post("/payment")
async def create_payment(request: Request):
    # Access your Stripe key — defined only in .env
    stripe_key = ENV_CONFIG["STRIPE_API_KEY"]
    # ... payment logic
    return JSONResponse({"success": True})
                    

How app/config.py Works

After lila init, app/config.py is clean and minimal. ConfigLoader loads .env, casts the framework keys and exposes them; the scaffold copies those values into module globals:

app/config.py

import os
from os import path
from lila.core.config import ConfigLoader, ENV_CONFIG

# Loads .env + framework defaults once and exports them as constants.
_cfg = ConfigLoader.load()
globals().update(_cfg)

# Project paths (not read from .env)
PATH_LOG_BASE_DIR = "app/logs"
PATH_TEMPLATE_NOT_FOUND = "lila/404"
PATH_TEMPLATES_HTML = "resources/html/"
PATH_TEMPLATES_MARKDOWN = "resources/markdown/"
PATH_UPLOADS = path.join(os.getcwd(), "public", "uploads")
                    

Framework variables are declared once in FRAMEWORK_SCHEMA inside lila/core/config.py; ENV_CONFIG reads the loaded, typed values. To change any value, edit .env and restart the server.

Loading & SECRET_KEY generation

ConfigLoader.load() runs once (it is idempotent) and caches the typed dict in memory for the process. App() calls it automatically, so importing lila.core.app directly still reads .env. There is no config_cache.py file and no separate production cache step.

SECRET_KEY is special: an empty value, a value shorter than 16 characters or a known placeholder makes get_secret_key() generate a strong key and persist it in .lila_secret (mode 0600) with a warning. Lila never signs sessions or CSRF tokens with an empty key. Rotate it with lila secret-key.

⚡

Performance Note

ENV_CONFIG reads values that were loaded at startup — it does not re-read .env on every access. This means there is no per-request disk I/O when using ENV_CONFIG in your route handlers.

API Reference

Method Returns Description
ENV_CONFIG["KEY"] any Get a value. Raises KeyError if not found.
ENV_CONFIG.get("KEY", default) any Get a value with a fallback default. Returns None if not found and no default given.
ENV_CONFIG.get_bool / get_int / get_list bool / int / list Typed helpers that never use bool("False").
"KEY" in ENV_CONFIG bool Check if a variable exists in the configuration.
ConfigLoader.load() dict Loads .env + defaults once and returns the typed dict (idempotent).
ConfigLoader.reload() dict Clears the cached values and loads again (useful in tests).
get_secret_key() / is_debug() str / bool Fail-safe signing key and typed debug flag.