Get AI summaries of any video or article — Sign up free
Python Tutorial: Securely Manage Passwords and API Keys with DotEnv thumbnail

Python Tutorial: Securely Manage Passwords and API Keys with DotEnv

Corey Schafer·
5 min read

Based on Corey Schafer's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.

TL;DR

Install python-dotenv with pip and load secrets at startup by calling load_dotenv() before reading environment variables.

Briefing

Using python-dotenv (imported as “dotenv” in code) to load environment variables from a local .env file lets developers keep API keys and other secrets out of source code while still making them easy to access at runtime. The practical payoff is twofold: secrets stay shareable with the project without being exposed in the repository, and the same loading approach works across operating systems.

The tutorial starts with the core workflow. Install the library with pip, create a .env file inside the project directory, and add sensitive values in simple key/value form (for example, API_KEY=ABCD1234). Then, in the Python script, import load_dotenv (written as “from dotenv import load_dotenv”), call load_dotenv() to populate environment variables, and read them via os.environ (e.g., os.getenv or direct os.environ access). A quick run confirms the secret becomes available to the program—without ever being hardcoded into the script.

Security and collaboration come next. Because .env files are exactly where secrets live, they must not be committed to version control. The guide recommends creating a .gitignore file and adding “.env” to it so the file won’t be pushed to platforms like GitHub. It also points to a gitignore generator site to produce a correct .gitignore for the user’s stack (Mac OS and Python in the example), helping avoid accidentally committing unrelated system files.

After the basic setup, the tutorial drills into .env syntax and common gotchas. Assignments must not include spaces around the equals sign. Comments are allowed either on their own line or at the end of a line, and blank lines can be used to organize sections. All values load as strings, so numeric values require explicit casting in Python if a different type is needed. Values containing spaces are allowed, and the preferred practice is to wrap them in quotes for clarity and reliability.

A notable debugging issue appears when an environment variable already exists on the machine. python-dotenv does not override existing systemwide environment variables by default, so a value set in .env may not show up as expected. Two fixes are offered: rename the variable in the .env file to avoid collisions, or pass override=True to load_dotenv() to force .env values to take precedence.

The tutorial also distinguishes single vs. double quotes. Single quotes treat content literally, while double quotes enable escape sequences such as \n for newlines—useful for multi-line secrets or text fields. Finally, it covers variable expansion: within .env, referenced variables use ${VAR_NAME} syntax (e.g., EMAIL=${username}@gmail.com), and this expanded content can still be wrapped in quotes.

Overall, the method becomes a go-to pattern for managing secrets per project: keep .env local, ignore it in git, load it at startup, and handle quoting, types, and override behavior correctly.

Cornell Notes

python-dotenv provides a clean way to store secrets like API keys in a project-local .env file and load them into Python at runtime. After installing the package, developers create a .env file, call load_dotenv() in the script, and read values from environment variables (e.g., via os.environ). The tutorial emphasizes security: .env must be excluded from version control using .gitignore, otherwise secrets can leak to GitHub. It also highlights .env syntax rules (no spaces around “=”, comments allowed, values are strings) and practical pitfalls like variable collisions with existing system environment variables. Handling quotes, escape sequences, and ${VAR} expansion ensures secrets and formatted text load correctly.

How does python-dotenv keep secrets out of source code while still making them usable in a script?

Secrets go into a project-local .env file as simple key/value pairs (e.g., API_KEY=ABCD1234). In Python, the script imports load_dotenv from dotenv, calls load_dotenv() to load those pairs into environment variables, and then reads the values using the os module (for example, os.environ or os.getenv). Running the script shows the secret is available to the program, but it was never hardcoded into the .py file.

Why is .gitignore essential when using a .env file, and what should be added?

A .env file contains the sensitive values, so committing it defeats the purpose of using environment variables. The tutorial recommends creating a .gitignore file and adding “.env” so git ignores the file during commits. It also notes that using a gitignore generator can help include other relevant entries (like Mac OS files) without accidentally committing unnecessary artifacts.

What are the key syntax rules for writing .env files correctly?

Variable assignments must not include spaces around the equals sign (KEY=value, not KEY = value). Comments can appear at the start of a line or at the end of a line. Blank lines are allowed for organization. Values load as strings, so numbers require casting in Python if a numeric type is needed. Spaces inside values are allowed, and wrapping them in quotes is recommended for readability and fewer surprises.

What happens when a variable already exists in the system environment, and how can it be fixed?

python-dotenv does not override existing environment variables by default. That means a value defined in .env may be ignored if the same variable name is already set systemwide. Two solutions are provided: (1) change the variable name in the .env file to avoid collisions, or (2) call load_dotenv with override=True to force .env values to replace existing ones.

How do single quotes, double quotes, and escape sequences affect .env values?

Single quotes treat content literally, which is useful for passwords containing special characters because sequences like backslash-n won’t be interpreted. Double quotes allow escape sequences such as \n to represent newlines. The tutorial demonstrates multi-line text behavior: single quotes can preserve line breaks as typed, while double quotes can use \n to produce line breaks when loaded.

How does variable expansion work inside .env files?

To reuse one variable inside another, .env uses ${VAR_NAME} syntax. For example, if username is set in .env, an email can be built as EMAIL=${username}@gmail.com. The expanded result can also be wrapped in quotes, including when the expanded value contains spaces.

Review Questions

  1. What security failure occurs if a .env file is committed to a public repository, and how does .gitignore prevent it?
  2. Why might a value in .env not appear in Python even after calling load_dotenv(), and what two remedies are available?
  3. When should you use single quotes vs. double quotes in a .env file, especially for passwords and newline characters?

Key Points

  1. 1

    Install python-dotenv with pip and load secrets at startup by calling load_dotenv() before reading environment variables.

  2. 2

    Store secrets in a project-local .env file using KEY=value pairs, then access them in Python via the os module.

  3. 3

    Never commit .env to version control; add “.env” to .gitignore to prevent accidental exposure on platforms like GitHub.

  4. 4

    Write .env syntax carefully: no spaces around “=”, comments are allowed, blank lines can organize sections, and all values load as strings.

  5. 5

    Handle type needs explicitly: cast numeric-looking strings to int/float in Python when required.

  6. 6

    Avoid collisions with systemwide environment variables—either rename the .env variable or use override=True to force replacement.

  7. 7

    Use quotes and escape sequences correctly: single quotes keep content literal, double quotes enable escapes like \n, and ${VAR} supports variable expansion.

Highlights

A .env file can hold an API key like API_KEY=ABCD1234, and load_dotenv() makes it available to Python without hardcoding secrets into the script.
Adding “.env” to .gitignore is the difference between safe secret management and accidental credential leaks to GitHub.
python-dotenv won’t override existing system environment variables by default, which can make .env changes appear to “not work.”
Single vs. double quotes matter: single quotes keep passwords literal, while double quotes allow escape sequences such as \n for newlines.
Variable expansion in .env uses ${VAR_NAME}, enabling derived values like EMAIL=${username}@gmail.com.

Topics

Mentioned