Configuration

Every application needs different settings for different environments — debug mode in development, real secrets in production, different database URLs for testing. This guide covers how to manage configuration cleanly.

Environment Variables

The simplest and most universal approach. Environment variables work everywhere — locally, in Docker, on cloud platforms — and keep secrets out of your source code:

import os
import responder

api = responder.API(
    debug=os.getenv("DEBUG", "false").lower() == "true",
    secret_key=os.environ["SECRET_KEY"],
    cors=os.getenv("CORS_ENABLED", "false").lower() == "true",
)

Some variables Responder handles automatically:

  • PORT — when set, the server binds to 0.0.0.0 on this port

Set variables in your shell:

$ export SECRET_KEY="your-secret-here"
$ export DEBUG=true
$ python app.py

Or in a .env file (don’t commit this to git):

SECRET_KEY=your-secret-here
DEBUG=true

Using .env Files

For local development, a .env file is convenient. Install python-dotenv and load it at the top of your app:

$ uv pip install python-dotenv
from dotenv import load_dotenv
load_dotenv()

import os
import responder

api = responder.API(
    secret_key=os.environ["SECRET_KEY"],
)

Add .env to your .gitignore — never commit secrets.

Configuration Class Pattern

For larger applications, a configuration class keeps things organized:

import os

class Config:
    SECRET_KEY = os.environ.get("SECRET_KEY", "dev-secret")
    DEBUG = os.environ.get("DEBUG", "false").lower() == "true"
    DATABASE_URL = os.environ.get("DATABASE_URL", "sqlite:///dev.db")
    CORS_ORIGINS = os.environ.get("CORS_ORIGINS", "").split(",")

config = Config()

api = responder.API(
    debug=config.DEBUG,
    secret_key=config.SECRET_KEY,
    cors=bool(config.CORS_ORIGINS[0]),
    cors_params={"allow_origins": config.CORS_ORIGINS},
)

This makes it easy to see all your settings in one place.

Secret Key

The secret_key is used to sign session cookies. If someone knows your secret key, they can forge session data and impersonate any user.

Rules:

  • Never use the default in production

  • Generate a random key: python -c "import secrets; print(secrets.token_hex(32))"

  • Store it in an environment variable, not in code

  • Rotate it if it’s ever compromised (this invalidates all sessions)

api = responder.API(secret_key=os.environ["SECRET_KEY"])

Debug Mode

Debug mode controls error page behavior:

  • On (debug=True): detailed error pages with tracebacks. Never use this in production — it exposes your source code.

  • Off (debug=False): generic error pages. This is the default.

api = responder.API(debug=True)  # development only

A common pattern is to read it from the environment:

api = responder.API(debug=os.getenv("DEBUG") == "true")

Allowed Hosts

In production, always set allowed_hosts to prevent Host header attacks. This should match the domain names your application serves:

api = responder.API(
    allowed_hosts=["example.com", "www.example.com"],
)

In development, you can use ["*"] (the default) or specific local addresses:

api = responder.API(allowed_hosts=["localhost", "127.0.0.1"])

Putting It All Together

A production-ready configuration setup:

import os
from dotenv import load_dotenv

load_dotenv()

import responder

api = responder.API(
    debug=os.getenv("DEBUG", "false") == "true",
    secret_key=os.environ["SECRET_KEY"],
    allowed_hosts=os.getenv("ALLOWED_HOSTS", "*").split(","),
    cors=bool(os.getenv("CORS_ORIGINS")),
    cors_params={
        "allow_origins": os.getenv("CORS_ORIGINS", "").split(","),
        "allow_methods": ["GET", "POST", "PUT", "DELETE"],
    },
)

With a .env file for local development:

SECRET_KEY=dev-secret-do-not-use-in-prod
DEBUG=true
ALLOWED_HOSTS=localhost,127.0.0.1
CORS_ORIGINS=http://localhost:3000

And environment variables set properly in production (via your cloud platform’s dashboard, Docker secrets, or a secrets manager).