python-dotenv for .env files
Overview
The `python-dotenv` library reads key-value pairs from a `.env` file and adds them to `os.environ`. It acts like a local bridge, simulating system environment variables during development without requiring you to set them manually in your shell. By using this library, you can manage configuration outside your codebase. This helps you avoid hardcoding sensitive information. Key functions include: - `load_dotenv(dotenv_path=None, override=False)`: Loads variables from a `.env` file into the system environment. Returns `True` if a file was found and loaded, or `False` otherwise. Does not raise an exception if the file is missing. - `dotenv_values(dotenv_path=None)`: Parses the `.env` file and returns a dictionary of the variables without modifying `os.environ`. Returns a `dict` of parsed keys and values. - `find_dotenv()`: Searches for a `.env` file by walking up the directory tree. Returns a `str` with the absolute path to the `.env` file, or an empty string if not found. When loading variables, a common trap is expecting `.env` to override existing system variables. import os from dotenv import load_dotenv os.environ['API_KEY'] = 'prod_key' # If .env contains API_KEY=dev_key load_dotenv() print(os.environ['API_KEY']) # Prints 'prod_key' By default, `load_dotenv()` will not overwrite existing environment variables. If you need the `.env` file to take precedence, you must explicitly call `load_dotenv(override=True)`.
Hardcoding secrets in your code is a major security risk, and setting environment variables manually in every terminal session is tedious. The `python-dotenv` library automates loading local configuration while keeping secrets out of version control.
Where used: FastAPI configuration, Database connection scripts, Local development scripts
Why learn this
- Load secrets locally without risking exposing them in Git
- Use different configuration values for development, testing, and production
- Standardize local development environments across your team
Code walkthrough
import os
from dotenv import load_dotenv
# Before loading
print(os.environ.get('API_KEY'))
# Load variables from .env into os.environ
load_dotenv()
# After loading
print(os.environ.get('API_KEY'))
Focus: load_dotenv()
Aha moment
import os
from dotenv import load_dotenv
# Environment already has: DB_HOST=production.db
# .env file has: DB_HOST=localhost
os.environ['DB_HOST'] = 'production.db'
load_dotenv()
print(os.environ.get('DB_HOST'))
Prediction: What does this print?
Common guess: `'localhost'`
By default, `load_dotenv()` does NOT overwrite existing environment variables. It only sets variables that don't already exist in `os.environ`.
Common mistakes
- Committing .env to version control: This accidentally leaks sensitive keys. Always add `.env` to your `.gitignore` and share a `.env.example` template instead.
- Assuming types are preserved: All loaded variables are strings. For example, `DEBUG=True` will return the string `'True'`, not a boolean value, requiring you to parse it manually.
- Confusing load_dotenv and dotenv_values: Calling `dotenv_values()` does not populate `os.environ`. It only returns a dictionary of the variables in the file. If you need the variables available system-wide in Python, you must use `load_dotenv()`.
Glossary
- version control
- A system that records changes to a file or set of files over time so that you can recall specific versions later, like Git. Example: `git commit`
- hardcoding
- Directly embedding data, like passwords or settings, right into the source code of a program instead of obtaining it from an external source. Example: `API_KEY = 'secret123'`
Recall questions
- What is the primary purpose of the `python-dotenv` library?
- Why is it important to use a `.env` file instead of putting secrets in your Python code?
- What is the difference between `load_dotenv()` and `dotenv_values()`?
Understanding checks
What is the output of this code, and why?
`'8080'`
Environment variables are always loaded as strings, even if they look like integers in the `.env` file.
Why does this print 'Feature is enabled!' when the .env says False?
The string `'False'` is truthy in Python.
`os.environ.get()` returns the string `'False'`. In Python, any non-empty string evaluates to `True` in a boolean context. You must explicitly check `== 'True'` or parse it.
Practice tasks
Force overwrite environment variables
Given this code that loads a `.env` file, modify it so that `load_dotenv` overwrites any existing environment variables with the values from the `.env` file. (Hint: look at the `override` parameter).
Challenge
Parse a boolean flag from dotenv
Write a snippet that loads `.env`, retrieves a `DEBUG` variable, and sets a Python boolean variable `is_debug` to `True` ONLY if the value is exactly the string `'True'` (or `'true'`). Fall back to `False` if it's not set.
Continue learning
Previous: os.environ and Environment Variables