init_app loads, copies every uppercase variable into app.config coerced to its type, and adds a context processor that hands client variables to your templates as envless.
from flask import Flask
from envless_env.flask import init_app
def create_app() -> Flask:
app = Flask(__name__)
init_app(app)
return appA variable named SECRET_KEY becomes Flask's secret key, SQLALCHEMY_DATABASE_URI configures Flask-SQLAlchemy, and a boolean named DEBUG arrives as a real bool. Config keys follow Flask's own rule, so a lowercase name is skipped there and still readable through env. Pass config=False to load without touching app.config.
init_app returns the same dict that load() returns, and raises LoadError if the load fails, so create_app stops before the app serves a request.
Client variables in templates
Every variable marked client in Envless is available in Jinja as envless. Server variables are not in it.
<script>
window.API_URL = {{ envless.PUBLIC_API_URL|tojson }};
</script>Reading elsewhere
Outside the app factory, read through env as anywhere else. init_app loads the shared store, so a blueprint, a CLI command or a Celery task in the same process sees the same values.
from flask import Blueprint
from envless_env.server import env
billing = Blueprint('billing', __name__)
@billing.get('/plans')
def plans() -> dict[str, object]:
return {'currency': env.BILLING_CURRENCY}Under envless run -- flask run, init_app still copies the values into app.config, but it reads them from the environment the CLI injected and makes no request.