envless-env is the Envless runtime for Python. It fetches your environment when your app starts, decrypts it in the process, fills os.environ with every name that is safe to set, and gives your code an env object that reads each variable coerced to the type you set in Envless. No .env files on disk, no python-dotenv, no os.environ['X'] typo that only fails in production.
pip install envless-envuv add envless-envpoetry add envless-envimport envless_env.register # noqa: F401
from envless_env.server import env
database_url = env.DATABASE_URL
port = env.PORTIt is the Python twin of @goenvless/env: the same loader, the same on-disk cache, the same rules for the process environment and the same error messages. A parity check in the Envless repository replays the same scenarios against both packages and one mock API before each release, from pagination and retries to which names are refused from os.environ. The one deliberate difference: the Python runtime reads ENVLESS_API_ENDPOINT when it runs, while the TypeScript package fixes its endpoint when it is built.
What this is, and what it is not
envless-env | envless-sdk | envless run | |
|---|---|---|---|
| Purpose | Loads variables into your running app | Administers a workspace from Python | Injects variables into any process |
| Runs | Inside your Python process, at boot | In scripts, back offices and CI | In front of your process, as the launcher |
| Credential | A machine key and a decryption key | An API key | envless login, or a machine key |
| Shape | env.DATABASE_URL | envless.variables.create(...) | envless run -- python app.py |
Use envless-env when your app should fetch its own variables at boot, typically in production with a machine key. Use envless run when you would rather keep every credential in the launcher, and the Python SDK when you want to create projects or write variables from code. The two runtimes combine: inside envless run, the Python runtime reads the values the CLI injected and makes no request at all.
The surfaces
| Import | What it gives you |
|---|---|
envless_env.server | env, optional, load, aload and override. Every variable, coerced. Use it in application code |
envless_env.client | env, optional and snapshot. Only the variables marked client, for templates and anything sent to a browser |
envless_env | env, load, aload, the errors and the crypto helpers. env here sees every variable, like server |
envless_env.register | Nothing. Importing it loads, so put it first |
envless_env.edge | load and aload with every input as an argument, for serverless functions |
envless_env.crypto | encrypt, decrypt, encrypt_with_key, decrypt_with_key, workspace_key and the rest of the recipe |
envless_env.django, .flask, .fastapi, .pydantic | Framework integrations |
python -m envless_env types | Writes envless_env_types.py, the views typed by name |
Design
Typed reads
A whole number reads back as an int, a fractional one as a float, and a boolean as a bool. A missing name raises instead of returning None, unless you read it through optional.
Secrets stay put
The env objects refuse to be pickled, iterated or printed with their values, so a log line or a debug page shows a count, never a secret.
Ambient wins
A variable already set in the process environment is never overwritten, and names that change how a process executes code, such as PATH, LD_PRELOAD or PYTHONPATH, are never written at all.
Fast cold starts
The ciphertext is cached under ~/.envless/cache for 15 minutes, shared with @goenvless/env, so a restart with ENVLESS_KEY makes no request and still decrypts in memory.