NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #1883 most downloaded on PyPI
simplified environment variable parsing
Last release 1 months ago
29 Aug 2026
Release timing varies
gaps range from 9 days to 8 months
Nearly every release is documented
notes for 59 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
10 years old
61 releases · first in 2016
Bump version and update changelog
Bump version and update changelog
Bump version and update changelog
One column per quarter.
Bump version and update changelog
Bump version and update changelog
Bump version and update changelog
Bug fixes:
.env files (regression from 15.0.0) (#464).
Thanks DougEdey-Slice for reporting.Bump version and update changelog
Bump version and update changelog
Features:
Env.read_env no longer mutates os.environ (#393). Values from .env files are loaded into the Env instance only. This comes with two breaking changes:
Env.read_env is now an instance method rather than a @staticmethod.
Env.read_env() -> env.read_env()verbose parameter of read_env is been removed.Other changes:
Bump version and update changelog
Bump version and update changelog
Bug fixes:
Other changes:
Bump version and update changelog
Bump version and update changelog
Features:
strip_whitespace param to FileAwareEnv (#431).
Thanks eandersons for the suggestion and PR.Other changes:
Bump version and update changelog
Bump version and update changelog
Features:
env.timedelta. (#434).
Thanks lucas-bremond for the suggestion and PR.Bump version and update changelog
Bump version and update changelog
Bump version and update changelog
Bump version and update changelog
Bump version and update changelog
Bump version and update changelog
Bug fixes:
env.list and env.dict to properly handle
default and subcast arguments (#406).
Thanks lucas-bremond for the PR.env to __all__ (#396).
Thanks daveflr for reporting.Changes:
recurse, verbose, override,
and return_path parameters to Env.read_env are now keyword-only.required argument to parser methods
is removed. Call a parser method without a default value to make it required.Add prefix parameter to Env constructor (#384). Thanks arthurc0102 for the suggestion.
Features:
prefix parameter to Env constructor (#384).
Thanks arthurc0102
for the suggestion.validate module from marshmallow (#385).Bug fixes:
Env.enum to allow by_value to be passed (#386).Add env singleton ([#194]). Thanks AndBondStyle for the suggestion.
Features:
env singleton ([#194]).
Thanks AndBondStyle for the suggestion.from environs import env
Changes:
default values are expected to be their in their deserialized form.
Backwards-incompatible: Passing serialized values to default
is no longer supported.from datetime import date, timedelta
import environs
# DO
enable_login = env.bool("ENABLE_LOGIN", True)
ttl = env.timedelta("TTL", default=timedelta(seconds=600))
release_date = env.date("RELEASE", date(2025, 1, 7))
numbers = env.list("FOO", [1.0, 2.0, 3.0], subcast=float)
# DON'T
enable_login = env.bool("ENABLE_LOGIN", "true")
ttl = env.timedelta("TTL", default=600)
release_date = env.date("RELEASE", "2025-01-07")
numbers = env.list("NUMBERS", "1,2,42", subcast=float)
The exceptions to this rule are the Django-related functions, which accept string defaults.
DATABASE_URL = env.dj_db_url("DATABASE_URL", default="postgresql://localhost:5432/mydb")
Typing: Add type hints for parser methods (#367). Thanks OkeyDev for the PR.
Features:
by_value param to Env.enum. Pass by_value=True to parse Enum by values instead of names.Other changes:
load_default param from parser methods. Use default instead.Env.enum's type param to enum.ignore_case param from Env.enum.allow_none, error_messages, and metadata params from parser methods.Env.enum allows passing an Enum as default.
Features:
Env.enum allows passing an Enum as default.Other changes:
Field classes private. Users should
not need to access these.Fix passing non-string default values to Env.timedelta (#369). Thanks tcleonard for reporting and thanks ddelange for the PR.
Env.timedelta can parse GEP-2257 duration strings (#366). Thanks ddelange for the PR.
Add return_path argument to Env.read_env to return the path of the parsed file (#362). Thanks senese for the suggestion and PR. NOTE: This is added as
Prevent DeprecationWarning getting raised by marshmallow 3.21.0 (333).
Fixes:
DeprecationWarning getting raised by marshmallow 3.21.0 (:issue:333).Other changes:
subcast_key argument of env.dict. Use subcast_keys instead.missing argument from Env methods. Use default instead.subcast argument from Env methods that don't use it.environs.__version__ variable.
Use importlib.metadata.version("environs") instead.Env.__repr__ and Env.__str__ no longer display environment variables, to prevent accidental exfiltration of sensitive data (#292). Thanks mro-rhansen2
Features:
Env.__repr__ and Env.__str__ no longer display environment variables, to prevent accidental exfiltration of sensitive data (#292).
Thanks mro-rhansen2 for the suggestion.Bug fixes:
None as default to env.list (#298).
Thanks lucas-bremond for reporting.env.read_env returns False if file not found (#294). Thanks rptaylor for the suggestion.
Allow default for env.json to be a dict or list (#240). Thanks tomgrin10 and bvanelli for the PRs.
Add delimiter argument to env.dict (#277). Thanks gregoiredx for the PR.
Features:
delimiter argument to env.dict (#277). Thanks gregoiredx for the PR.Other changes:
Allow callables or custom marshmallow fields to be passed to subcast, subcast_keys, and subcast_values. (#241). Thanks bvanelli for the PR.
Address warning about passing metadata in newer versions of marshmallow.
Bug fixes:
Other changes:
Fix env.url and other parsers that take field keyword arguments (#227). Thanks KochankovID for the PR.
Bug fixes:
env.url and other parsers that take field keyword arguments (#227).
Thanks KochankovID for the PR.Allow default for env.path to be a pathlib.Path (#228). Thanks KochankovID for the PR.
Bug fixes:
env.path to be a pathlib.Path (#228).
Thanks KochankovID for the PR.Fix compatibility with marshmallow>=3.13.0 so that no DeprecationWarnings are raised (#224).
Bug fixes:
Handle JSON decoding errors when using env.json (#212). Thanks bvanelli for the PR.
Apply variable expansion to default values (#204). Thanks rjcohn for the PR.
Rename subcast_key argument of env.dict to subcast_keys for consistency with subcast_values. subcast_key is deprecated.
Deprecations:
subcast_key argument of env.dict to subcast_keys
for consistency with subcast_values. subcast_key is deprecated.Features: - Add time parser (#191).
Features:
Add delimiter param to env.list (#184).
Features:
Thanks tomgrin10 for the PRs.
Bug fixes:
ParserMethod typing (#186 (comment)).
Thanks hukkinj1 for the PR.Other changes:
eager=False), parser methods return None
for missing or invalid values.
Note: This may break code that depended on parser methods returning marshmallow.missing,
but this behavior was not documented nor tested and therefore is not considered public API._Backwards-incompatible_: Rename subcast param of env.dict to subcast_values for consistency with subcast_keys.
subcast param of env.dict to subcast_values for consistency with subcast_keys.Variable proxying using the {{VAR}} syntax is deprecated and will be removed in environs 9.0.0. Use variable expansion using ${VAR} instead.
Features:
MY_VAR=${MY_OTHER_VAR:-mydefault} (#164).
Thanks gnarvaja for the PR.Deprecations:
{{VAR}} syntax is deprecated
and will be removed in environs 9.0.0.
Use variable expansion using ${VAR} instead.# Before
export MAILGUN_LOGIN=sloria
export SMTP_LOGIN={{MAILGUN_LOGIN}}
# After
export MAILGUN_LOGIN=sloria
export SMTP_LOGIN=${MAILGUN_LOGIN}
from environs import Env
env = Env(expand_vars=True)
SMTP_LOGIN = env.str("SMTP_LOGIN") # => 'sloria'
Bug fixes:
dj_db_url, dj_email_url, dj_cache_url,
and custom parsers (#121).
Thanks hukkinj1 for reporting.Other changes:
typing.Optional (171).Fix behavior of recurse=True when custom filepath is passed to env.read_env (#100). Thanks ribeaud and timoklimmer for the help.
Bug fixes:
env.read_env
(#100). Thanks ribeaud and timoklimmer for the help.Other changes:
env.read_env is no longer allowed and will raise a ValueError.
Only file paths or file names should be passed.Add subcast_key argument to env.dict (#151). Thanks AugPro for the suggestion and PR.
Fix error when parsing empty list with subcast #137. Thanks [sabdouni] for the catch and patch.
log_level accepts lower-cased log level names and rejects invalid names (#138). Thanks gnarvaja for the PR.
Add dj_cache_url for caching Django cache URLs (requires installing with [django]) (#126). Thanks epicserve for the suggestion and PR.
Improve typings and run mypy with dependencies type annotations (#115).
_Backwards-incompatible_: Remove stream argument from read_env, since it had no effect (#114).
Add deferred validation via the eager parameter and env.seal() (#56). Thanks robertlagrant for the suggestion.
Features:
eager parameter and env.seal() (#56).
Thanks robertlagrant for the suggestion.Other changes:
Default parser methods are now defined as bound methods. This enables static analysis features, e.g. autocomplete (#103). Thanks rugleb for the sugges
Features:
import environs
env = environs.Env()
# Below conflicts with built-in `url` method.
# In <6.0.0, this would override the built-in method.
# In >=6.0.0, this raises an error:
# environs.ParserConflictError: Env already has a method with name 'url'. Use a different name.
@env.parser_for("url")
def https_url(value):
return "https://" + value
Bug fixes:
Other changes:
Env.__parser_map__ to Env.__custom_parsers__.Fix behavior when recursively searching for a specified file (#96). Thanks ribeaud for the catch and patch.
Changes: - Improve typings.
Changes:
Use raise from to improve tracebacks.
Features:
env.log_level (#7).raise from to improve tracebacks.Other changes:
Add env.path (#81). Thanks umrashrf for the suggestion.
Reset prefix when an exception is raised within an env.prefixed() context (#78). Thanks rcuza for the catch and patch.
Fix behavior when passing a dict value as the default to env.dict (#76). Thanks c-w for the PR.
Bug fixes:
Support:
env.read_env
(#66).
Thanks nvtkaszpir and
c-w.Fix compatibility with marshmallow 3.0.0>=rc6.
Bug fixes:
Fix accessing proxied envvars when using env.prefixed (#72). Thanks Kamforka for the catch and patch.
Bug fixes:
env.prefixed
(#72).
Thanks Kamforka for the catch and patch.EnvError subclasses ValueError (#50). Thanks alexpirine.
EnvError subclasses ValueError (#50).
Thanks alexpirine.Use python-dotenv for parsing .env files. Env.read_env behaves mostly the same except that a warning isn't raised by default if a .env file isn\'t fou
Env.read_env behaves
mostly the same except that a warning isn't raised by default if a
.env file isn't found. Pass verbose=True to raise a warning._Backwards-incompatible_: Env.read_env raises a warning instead of an error when .env isn\'t found (#10). Thanks lachlancooper for the suggestion.
Features:
Env.read_env raises a warning instead of
an error when .env isn't found
(#10). Thanks
lachlancooper for the
suggestion.pip install environs[django], which enables env.dj_db_url and
env.dj_email_url.Fix compatibility with marshmallow 3 beta.
Features:
Add recurse parameter to Env.read_env (#9). Thanks gthank for the PR.
Nothing published for this version
Add url parser that returns a urllib.parse.ParseResult (#6). Thanks IlyaSemenov for the suggestion.
Features:
url parser that returns a urllib.parse.ParseResult
(#6). Thanks
IlyaSemenov for the suggestion.Bug fixes:
Env gets its own parser map, so calling
env.parser_for for one instance doesn't affect other instances.Add Env.read_env method for reading .env files.
Env.read_env method for reading .env files.Support for proxied variables (#2).
Your coding agent can read these notes before it upgrades. Set up the MCP server →