{"id":2019,"library":"environs","title":"environs: simplified environment variable parsing","description":"environs is a Python library (current version 15.0.1) designed for simplified parsing of environment variables, aligning with the Twelve-Factor App methodology for separating configuration from code. It provides robust type-casting, validation, and flexible parsing of various data types including lists, dictionaries, dates, and URLs. It also integrates seamlessly with `.env` files. environs is actively maintained and has a steady release cadence.","status":"active","version":"15.0.1","language":"en","source_language":"en","source_url":"https://github.com/sloria/environs","tags":["environment variables","configuration","dot-env","12-factor-app","type-casting","validation"],"install":[{"cmd":"pip install environs","lang":"bash","label":"Install environs"}],"dependencies":[{"reason":"Required for reading .env files.","package":"python-dotenv","optional":false},{"reason":"Used under the hood for validation, deserialization, and serialization.","package":"marshmallow","optional":false},{"reason":"Optional dependency for Django database URL parsing.","package":"dj-database-url","optional":true},{"reason":"Optional dependency for Django email URL parsing.","package":"dj-email-url","optional":true},{"reason":"Optional dependency for Django cache URL parsing.","package":"django-cache-url","optional":true}],"imports":[{"note":"While `from environs import env` works by importing a pre-instantiated `Env` object, directly importing `Env` and creating an instance (e.g., `env = Env()`) offers more control and clarity, especially when dealing with different environments or `eager=False`.","wrong":"from environs import env","symbol":"Env","correct":"from environs import Env"}],"quickstart":{"code":"import os\nfrom environs import Env\nfrom urllib.parse import urlparse\nimport logging\n\n# For demonstration, set some environment variables\nos.environ['GITHUB_USER'] = 'test_user'\nos.environ['MAX_CONNECTIONS'] = '10'\nos.environ['SHIP_DATE'] = '1984-06-25'\nos.environ['ENABLE_LOGIN'] = 'true'\nos.environ['API_KEY'] = 'some_secret_key'\nos.environ['LOG_LEVEL'] = 'INFO'\nos.environ['MY_API_URL'] = 'https://api.example.com/v1'\n\n# Initialize Env object\nenv = Env()\n\n# For local development, uncomment and ensure python-dotenv is installed:\n# with open('.env', 'w') as f:\n#     f.write('ANOTHER_VAR=hello\\n')\n# env.read_env() # Reads from .env file if it exists\n\n# Required variables\ngh_user = env('GITHUB_USER')\nprint(f\"GitHub User: {gh_user}\")\n\n# Casting to specific types\nmax_connections = env.int('MAX_CONNECTIONS', default=5) # default if not set\nprint(f\"Max Connections: {max_connections} (type: {type(max_connections)})\")\n\nship_date = env.date('SHIP_DATE')\nprint(f\"Ship Date: {ship_date} (type: {type(ship_date)})\")\n\nenable_login = env.bool('ENABLE_LOGIN', default=False)\nprint(f\"Enable Login: {enable_login} (type: {type(enable_login)})\")\n\napi_key = env('API_KEY') # No type cast, defaults to str\nprint(f\"API Key: {api_key}\")\n\nlog_level = env.log_level('LOG_LEVEL', default=logging.DEBUG)\nprint(f\"Log Level: {log_level} (type: {type(log_level)})\")\n\n# URL parsing\nmy_api_url = env.url('MY_API_URL')\nprint(f\"API URL: {my_api_url.scheme}://{my_api_url.netloc} (type: {type(my_api_url)})\")\n\n# Example of a missing variable with default\nfeature_flag = env.bool('FEATURE_X', default=False)\nprint(f\"Feature X enabled: {feature_flag}\")\n\n# Example of a required variable not set (will raise EnvValidationError)\n# try:\n#    missing_var = env('MISSING_REQUIRED_VAR')\n# except Exception as e:\n#    print(f\"Error: {e}\")\n","lang":"python","description":"This quickstart demonstrates how to initialize `environs`, read various environment variables with type-casting, provide default values, and parse URLs. It shows how `environs` helps manage different data types from string-based environment variables. For local development with `.env` files, ensure `python-dotenv` is installed and `env.read_env()` is called."},"warnings":[{"fix":"Use the `Env` instance directly as a callable, e.g., `env('VAR_NAME')` for required variables or `env('VAR_NAME', default='fallback')` for optional variables with a default.","message":"The `env.get()` method was removed in `environs` version 1.0.0. Attempting to use it will result in an `AttributeError`.","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"Ensure `pip install python-dotenv` is run and place `env.read_env()` at the beginning of your configuration loading logic.","message":"Reading `.env` files is not automatic. You must explicitly call `env.read_env()` early in your application's lifecycle to load variables from `.env` files into the `Env` instance. This functionality also requires `python-dotenv` to be installed.","severity":"gotcha","affected_versions":"all"},{"fix":"Always use the `env` object provided by `environs` (e.g., `env('VAR_NAME')`, `env.int('NUMBER')`) throughout your application for configuration values to ensure consistency and proper type-casting. Avoid directly accessing `os.environ` for `environs`-managed values after initialization.","message":"`environs` operates on its own internal state and does not directly mutate `os.environ` when `env.read_env()` is called or variables are accessed. If you later try to access `os.environ` directly, it will not reflect the values loaded or overridden by `environs` from `.env` files.","severity":"gotcha","affected_versions":"all"},{"fix":"If a string URL is needed, use `from environs import Env, validate; url_string = env.str('MY_URL', validate=validate.URL())`. When providing a `default` value to `env.url()`, it must also be a `urllib.parse.ParseResult` object.","message":"The `env.url()` method returns a `urllib.parse.ParseResult` object, not a plain string. If you require the URL as a string, you should explicitly use `env.str(..., validate=validate.URL())`.","severity":"gotcha","affected_versions":"all"},{"fix":"Always call `env.seal()` after parsing all your required and optional environment variables if you are using validation, particularly with deferred (non-eager) validation.","message":"When using validators with `environs` (especially when `Env` is initialized with `eager=False`), you must explicitly call `env.seal()` after all environment variables have been parsed to trigger deferred validation. Failing to do so can lead to validation errors not being raised until much later or incorrect behavior.","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-04-09T00:00:00.000Z","next_check":"2026-07-08T00:00:00.000Z"}