Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes
How-tos

Secure Python Configs with Environment Variables

Learn how to replace hardcoded secrets in your Python code with environment variables using .env files and python-dotenv for safer, portable configuration.

July 2026 7 min read 2 views 0 hearts

Hardcoding passwords, API keys, or database URLs directly into your Python code is a security risk. You might think, "I'll just remove them before pushing to GitHub," but mistakes happen. And when they do, your sensitive data ends up exposed in public repositories for anyone to find.

The smarter way? Environment variables. They keep secrets out of your codebase and let you manage configurations across different environments safely.

What Are Environment Variables?

Think of environment variables as key-value pairs stored outside your application. They exist at the system level — whether that's your local development machine, a staging server, or production. Your Python app reads them when it runs, but the values themselves never end up in the code files.

For example, instead of writing this:

db_password = "SuperSecret123!"

You store the password in an environment variable named DB_PASSWORD, then read it in your code with os.getenv("DB_PASSWORD"). The actual password lives elsewhere, not in your repository.

Why This Matters

If you've ever accidentally committed an API key to GitHub, you know the feeling — scrambling to revoke keys and clean up commit history. Even private repositories can be compromised. Environment variables eliminate this problem entirely.

Plus, it makes your app portable. The same code can run on your laptop, a colleague's machine, and production servers — all using different credentials without changing a single line of code.

Setting Up Environment Variables

There are several ways to do this, depending on your platform:

On Linux/macOS:

export DB_PASSWORD="SuperSecret123!"

On Windows (Command Prompt):

set DB_PASSWORD="SuperSecret123!"

On Windows (PowerShell):

$env:DB_PASSWORD="SuperSecret123!"

But manually setting variables every time you open a terminal is tedious. That's where .env files come in.

Using .env Files for Development

Create a file named .env in your project root. Never commit this file to version control. Add it to your .gitignore immediately:

.env

Your .env file might look like this:

DB_HOST=localhost
DB_PORT=5432
DB_NAME=pythonskillset_prod
DB_USER=admin
DB_PASSWORD=SuperSecret123!
API_KEY=your_api_key_here
SECRET_KEY=production_secret

Now install python-dotenv to load these variables:

pip install python-dotenv

Loading Variables in Your Python Code

Here's a clean pattern for loading environment variables:

import os
from dotenv import load_dotenv

# Load .env file (only in development)
load_dotenv()

# Read variables with defaults where appropriate
db_host = os.getenv("DB_HOST", "localhost")
db_port = int(os.getenv("DB_PORT", 5432))
db_name = os.getenv("DB_NAME", "pythonskillset_dev")
db_user = os.getenv("DB_USER", "devuser")
db_password = os.getenv("DB_PASSWORD")
api_key = os.getenv("API_KEY")
secret_key = os.getenv("SECRET_KEY")

# Validate required variables exist
required_vars = ["DB_PASSWORD", "API_KEY", "SECRET_KEY"]
for var in required_vars:
    if not os.getenv(var):
        raise EnvironmentError(f"Missing required environment variable: {var}")

Notice the pattern: provide sensible defaults for non-sensitive values like host and port, but require critical secrets to be explicitly set.

Best Practices for Production

In production, don't use .env files. Instead, set environment variables through your hosting platform:

  • Docker: Pass via -e flags or an env_file directive
  • Kubernetes: Use Secrets objects mounted as environment variables
  • Heroku: Use the config vars dashboard
  • AWS Elastic Beanstalk: Set in environment properties
  • GitHub Actions: Store as repository secrets

Your code never changes — it just reads os.getenv() regardless of where it runs.

Common Mistakes to Avoid

Mistake 1: Committing .env files Double-check your .gitignore. If you've already committed one, use git rm --cached .env to untrack it, then rotate any exposed credentials.

Mistake 2: Hardcoding fallbacks for secrets It's tempting to write os.getenv("DB_PASSWORD", "default") for testing. Don't. If someone forgets to set the variable, your app should fail loudly, not silently use a default password.

Mistake 3: Loading .env in production Your .env file doesn't exist on production servers. The load_dotenv() call will simply do nothing if the file is missing, but it's cleaner to conditionally load it:

if os.path.exists(".env"):
    load_dotenv()

A Real-World Example from PythonSkillset

At PythonSkillset, we use this approach for all our internal tools. One script that processes user analytics needs access to our database and an external API. The development team each has their own .env file with test credentials, while the production server gets its variables from Kubernetes Secrets.

When a new developer joins, they clone the repository, copy our template .env.example file (which has dummy values), and fill in their own credentials. The code itself never changes between environments.

Testing With Environment Variables

When writing tests, override environment variables temporarily:

import os
from unittest.mock import patch

def test_database_connection():
    with patch.dict(os.environ, {"DB_PASSWORD": "test_password"}):
        # Your test code here
        assert os.getenv("DB_PASSWORD") == "test_password"

This way, your tests don't depend on your local .env file.

Wrapping Up

Environment variables are one of those small practices that make a huge difference in software security. They're simple to implement, work everywhere Python runs, and protect you from accidental exposure.

Start today — find any hardcoded secrets in your projects and move them into environment variables. Your future self (and your users) will thank you.

Comments

Questions, corrections, and tips stay visible for everyone reading this page.

0 in thread

Join the discussion

Shown next to your comment.

Up to 4,000 characters

No comments yet

Be the first to leave a note — it helps the next reader.