Environment Variables for Python and Django Projects

Abstract generated cover for Environment Variables for Python and Django Projects.

Environment variables are one of the normal ways to configure Python and Django projects. They are especially useful for values that change between environments:

  • secret keys
  • API tokens
  • database URLs
  • debug flags
  • allowed hosts
  • feature flags
  • service URLs The reason is simple:

Code should be the same across environments, but configuration often changes. Your local machine, staging server, and production server should not need different code just because they use different credentials.

The Mental Model

Environment variables are values provided by the operating environment. Python can read them with `os.environ`:

import os

debug = os.environ.get("DEBUG") == "1"

In production, these values may come from the server, deployment platform, container environment, or process manager. In local development, they often come from a `.env` file. The `.env` file is a convenience for local development. It is not the source code.

Keep Secrets Out of Git

Secrets should not be committed. That includes:

  • API tokens
  • database passwords
  • private keys
  • production secret keys
  • OAuth client secrets
  • webhook signing secrets A real `.env` file should usually be ignored: ```plain text .env .env.local
Commit an example instead:
```plain text
.env.example

The example file shows what variables are required without exposing real values.

Defaults

Not every environment variable needs to be required. Some values can have safe local defaults:

port = int(os.environ.get("PORT", "8000"))

Others should fail clearly if missing:

secret_key = os.environ["SECRET_KEY"]

The difference matters. If a missing variable would make the app insecure or broken, fail early. If a missing variable has an obvious safe default, use the default.

Validate Configuration

One common mistake is letting bad configuration fail much later. For example, if a project requires a Notion token and database ID, it should check for both before trying to sync. Bad behavior: ```plain text Invalid request URL

Better behavior:
```plain text
SYNC_NOTION=1 requires NOTION_TOKEN and NOTION_BLOG_DATABASE_ID.

Clear config errors save debugging time. This matters especially for projects that need to run on another machine.

Django Settings

Django settings often read environment variables. Example:

import os

SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
DEBUG = os.environ.get("DJANGO_DEBUG") == "1"
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "").split(",")

For production, `DEBUG` should be false. `SECRETKEY` should be private. `ALLOWEDHOSTS` should match the domains the site uses. The exact structure can vary, but the principle is stable:

Settings should make environment-specific values explicit.

.env Parsing Is Still Code

It is tempting to treat `.env` loading as trivial. But parsing config is still code. Values may be quoted. Lines may have spaces. Some values may be URLs. Some values may accidentally wrap. If your project depends on `.env` loading, handle errors clearly and test important edge cases. This is especially true for deployment scripts and dev startup scripts.

Common Mistakes

Mistake 1: Committing real `.env` files

This can leak secrets. Ignore real environment files and commit examples only.

Mistake 2: Silently skipping required config

If a feature is required, fail clearly when config is missing. Silent behavior creates confusion.

Mistake 3: Using production secrets locally

Local development should usually use local credentials or limited tokens. Avoid making every local test capable of touching production data.

Where This Shows Up in Real Projects

Environment variables appear in nearly every backend project:

  • Django settings
  • Notion sync scripts
  • database connections
  • deployment commands
  • API integrations
  • static site publishing
  • email providers
  • payment providers The more services a project touches, the more important clear configuration becomes. Good environment handling makes a project easier to clone, deploy, and debug.

Key Takeaways

  • Environment variables keep configuration outside code.
  • Real secrets should stay out of Git.
  • Use `.env.example` to document required values.
  • Fail clearly when required config is missing.
  • Use safe defaults only when they are actually safe.
  • Treat config loading as real code worth testing.

    Related Articles

  • Python Virtual Environments Explained

  • Django Project Structure Explained
  • VPS Deployment Basics for Developers

← Back to Blog Index