Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
run: |
pip install -r requirements-docs.txt
pip install -e .
mkdocs build
zensical build

- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
Expand Down
16 changes: 2 additions & 14 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,6 @@ coverage.xml
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

Expand All @@ -90,9 +80,6 @@ ipython_config.py
# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

Expand All @@ -112,7 +99,7 @@ venv.bak/
# Rope project settings
.ropeproject

# mkdocs documentation
# zensical documentation
/site

# mypy
Expand All @@ -125,5 +112,6 @@ dmypy.json

### Python Patch ###
.venv/
uv.lock

# End of https://www.gitignore.io/api/python
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,9 @@ os.PathLike]` instead of just `os.PathLike` (#347 by [@bbc2]).
[@JYOuyang]: https://github.com/JYOuyang
[@burnout-projects]: https://github.com/burnout-projects
[@cpackham-atlnz]: https://github.com/cpackham-atlnz

<!-- Releases -->

[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v1.2.2...HEAD
[1.2.2]: https://github.com/theskumar/python-dotenv/compare/v1.2.1...v1.2.2
[1.2.1]: https://github.com/theskumar/python-dotenv/compare/v1.2.0...v1.2.1
Expand Down
12 changes: 4 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
Contributing
============
# Contributing

All the contributions are welcome! Please open [an
issue](https://github.com/theskumar/python-dotenv/issues/new) or send us
Expand All @@ -18,18 +17,15 @@ or with [tox](https://pypi.org/project/tox/) installed:

$ tox


Use of pre-commit is recommended:

$ uv run precommit install


Documentation is published with [mkdocs]():
Documentation is published with [zensical](https://zensical.org/) and follows
the approach established by [Diátaxis](https://diataxis.fr/):

```shell
$ uv pip install -r requirements-docs.txt
$ uv pip install -e .
$ uv run mkdocs serve
$ make serve-docs
```

Open http://127.0.0.1:8000/ to view the documentation locally.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@ coverage:

coverage-html: coverage
coverage html

serve-docs:
uv pip install -r requirements-docs.txt
uv pip install -e .
uv run zensical serve
172 changes: 4 additions & 168 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,7 @@ python-dotenv reads key-value pairs from a `.env` file and can set them as
environment variables. It helps in the development of applications following the
[12-factor](https://12factor.net/) principles.

- [Getting Started](#getting-started)
- [Other Use Cases](#other-use-cases)
- [Load configuration without altering the environment](#load-configuration-without-altering-the-environment)
- [Parse configuration as a stream](#parse-configuration-as-a-stream)
- [Load .env files in IPython](#load-env-files-in-ipython)
- [Command-line Interface](#command-line-interface)
- [File format](#file-format)
- [Multiline values](#multiline-values)
- [Variable expansion](#variable-expansion)
- [Related Projects](#related-projects)
- [Acknowledgements](#acknowledgements)
> **[Read the full documentation](https://theskumar.github.io/python-dotenv/)**

## Getting Started

Expand Down Expand Up @@ -73,163 +63,9 @@ like `${DOMAIN}`, as bare variables such as `$DOMAIN` are not expanded.
You will probably want to add `.env` to your `.gitignore`, especially if it
contains secrets like a password.

See the section "[File format](#file-format)" below for more information about what you can write in a `.env` file.

## Other Use Cases

### Load configuration without altering the environment

The function `dotenv_values` works more or less the same way as `load_dotenv`,
except it doesn't touch the environment, it just returns a `dict` with the
values parsed from the `.env` file.

```python
from dotenv import dotenv_values

config = dotenv_values(".env") # config = {"USER": "foo", "EMAIL": "foo@example.org"}
```

This notably enables advanced configuration management:

```python
import os
from dotenv import dotenv_values

config = {
**dotenv_values(".env.shared"), # load shared development variables
**dotenv_values(".env.secret"), # load sensitive variables
**os.environ, # override loaded values with environment variables
}
```

### Parse configuration as a stream

`load_dotenv` and `dotenv_values` accept [streams][python_streams] via their
`stream` argument. It is thus possible to load the variables from sources other
than the filesystem (e.g. the network).

```python
from io import StringIO

from dotenv import load_dotenv

config = StringIO("USER=foo\nEMAIL=foo@example.org")
load_dotenv(stream=config)
```

### Load .env files in IPython

You can use dotenv in IPython. By default, it will use `find_dotenv` to search for a
`.env` file:

```python
%load_ext dotenv
%dotenv
```

You can also specify a path:

```python
%dotenv relative/or/absolute/path/to/.env
```

Optional flags:

- `-o` to override existing variables.
- `-v` for increased verbosity.

### Disable load_dotenv

Set `PYTHON_DOTENV_DISABLED=1` to disable `load_dotenv()` from loading .env
files or streams. Useful when you can't modify third-party package calls or in
production.

## Command-line Interface

A CLI interface `dotenv` is also included, which helps you manipulate the `.env`
file without manually opening it.

```shell
$ pip install "python-dotenv[cli]"
$ dotenv set USER foo
$ dotenv set EMAIL foo@example.org
$ dotenv list
USER=foo
EMAIL=foo@example.org
$ dotenv list --format=json
{
"USER": "foo",
"EMAIL": "foo@example.org"
}
$ dotenv run -- python foo.py
```

Run `dotenv --help` for more information about the options and subcommands.

## File format

The format is not formally specified and still improves over time. That being
said, `.env` files should mostly look like Bash files. Reading from FIFOs (named
pipes) on Unix systems is also supported.

Keys can be unquoted or single-quoted. Values can be unquoted, single- or
double-quoted. Spaces before and after keys, equal signs, and values are
ignored. Values can be followed by a comment. Lines can start with the `export`
directive, which does not affect their interpretation.

Allowed escape sequences:

- in single-quoted values: `\\`, `\'`
- in double-quoted values: `\\`, `\'`, `\"`, `\a`, `\b`, `\f`, `\n`, `\r`, `\t`, `\v`

### Multiline values

It is possible for single- or double-quoted values to span multiple lines. The
following examples are equivalent:

```bash
FOO="first line
second line"
```

```bash
FOO="first line\nsecond line"
```

### Variable without a value

A variable can have no value:

```bash
FOO
```

It results in `dotenv_values` associating that variable name with the value
`None` (e.g. `{"FOO": None}`. `load_dotenv`, on the other hand, simply ignores
such variables.

This shouldn't be confused with `FOO=`, in which case the variable is associated
with the empty string.

### Variable expansion

python-dotenv can interpolate variables using POSIX variable expansion.

With `load_dotenv(override=True)` or `dotenv_values()`, the value of a variable
is the first of the values defined in the following list:

- Value of that variable in the `.env` file.
- Value of that variable in the environment.
- Default value, if provided.
- Empty string.

With `load_dotenv(override=False)`, the value of a variable is the first of the
values defined in the following list:

- Value of that variable in the environment.
- Value of that variable in the `.env` file.
- Default value, if provided.
- Empty string.
See the [file format specification](https://theskumar.github.io/python-dotenv/reference/file-format/)
for full details on `.env` syntax, multiline values, escape sequences, and
variable expansion.

## Related Projects

Expand Down
1 change: 0 additions & 1 deletion docs/changelog.md

This file was deleted.

1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--8<-- "CHANGELOG.md"
1 change: 0 additions & 1 deletion docs/contributing.md

This file was deleted.

1 change: 1 addition & 0 deletions docs/contributing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--8<-- "contributing.md"
88 changes: 88 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
icon: lucide/rocket
---

# Getting Started

This tutorial walks you through installing python-dotenv and using it to load
environment variables from a `.env` file.

## Installation

=== "`pip`"

```shell
pip install python-dotenv
```

=== "`uv`"

```shell
uv add python-dotenv
```

## Create a `.env` file

Add a `.env` file to the root of your project:

```
.
├── .env
└── app.py
```

Write your configuration as key-value pairs:

```bash
# .env
DOMAIN=example.org
ADMIN_EMAIL=admin@${DOMAIN}
ROOT_URL=${DOMAIN}/app
```

If you use variables in values, ensure they are surrounded with `{` and `}`,
like `${DOMAIN}`, as bare variables such as `$DOMAIN` are not expanded. See
[Variable expansion](reference/file-format.md#variable-expansion) for the full
syntax.

!!! tip

Add `.env` to your `.gitignore`, especially if it contains secrets.

## Load the `.env` file

In your Python application:

```python
from dotenv import load_dotenv
import os

load_dotenv()

domain = os.getenv("DOMAIN")
print(domain) # example.org
```

`load_dotenv()` looks for a `.env` file starting in the same directory as the
calling script, walking up the directory tree until it finds one. Each key-value
pair is added to `os.environ`.

## How it works

By default, `load_dotenv()`:

- Searches for a `.env` file automatically using `find_dotenv()`.
- Reads each key-value pair and adds it to `os.environ`.
- **Does not override** existing environment variables. Pass `override=True` to change this.

```python
# Override existing environment variables
load_dotenv(override=True)
```

## Next steps

- [Configuration Patterns](guides/configuration.md): load config as a dict, layer multiple `.env` files.
- [Command-line Interface](guides/cli.md): manage `.env` files and run commands from the terminal.
- [File Format](reference/file-format.md): full specification of `.env` file syntax.
- [Python API Reference](reference/api.md): all functions and their parameters.
Loading