How to Manage Environment-Specific Configurations in FastAPI: Local, Staging, and Production

Manage environment-specific configurations in FastAPI by using a centralized Pydantic Settings class with an EnvironmentOption enum, loading values from environment variables or .env files, and gating features like API docs and HTTPS enforcement based on the ENVIRONMENT flag.

The benavlabs/fastapi-boilerplate repository demonstrates a robust pattern for managing environment-specific configurations through a single source of truth. By centralizing all settings in Pydantic models and using an enumeration to distinguish between local, staging, and production deployments, the codebase achieves deterministic, environment-aware behavior without scattering conditional logic throughout the application.

Core Configuration Architecture

The configuration system lives in src/app/core/config.py and relies on Pydantic's BaseSettings to handle environment variable parsing and validation.

Environment Enumeration

The EnvironmentOption enum defines the three supported deployment targets:

class EnvironmentOption(str, Enum):
    LOCAL = "local"
    STAGING = "staging"
    PRODUCTION = "production"

This enum is used to type-check the ENVIRONMENT variable across the entire application, ensuring only valid values are accepted.

Settings Composition

The EnvironmentSettings class holds the current environment flag, defaulting to local development:

class EnvironmentSettings(BaseSettings):
    ENVIRONMENT: EnvironmentOption = EnvironmentOption.LOCAL

The main Settings class combines multiple BaseSettings subclasses (such as PostgresSettings and RedisCacheSettings) into a single global singleton. It automatically loads values from a .env file located at the project root:

class Settings(EnvironmentSettings, PostgresSettings, ...):
    model_config = SettingsConfigDict(
        env_file=os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "..", ".env")
    )

settings = Settings()

Switching Between Environments

To manage environment-specific configurations, you manipulate the ENVIRONMENT variable and associated settings in your .env file or hosting platform.

Basic Environment Selection

Set the ENVIRONMENT variable to switch contexts:


# .env (staging example)

ENVIRONMENT=staging
APP_NAME="My FastAPI App – Staging"
POSTGRES_SERVER=staging-db.example.com
REDIS_CACHE_HOST=staging-redis.example.com

When the application starts, settings.ENVIRONMENT reflects this value. You can access it anywhere in the code to adjust behavior:


# src/app/api/v1/health.py

response = {
    "environment": settings.ENVIRONMENT.value,
    # ...

}

Optional Per-Environment Files

While the boilerplate defaults to a single .env file, you can maintain separate files (.env.local, .env.staging, .env.prod) and deploy the appropriate file as .env during your CI/CD pipeline. Alternatively, inject variables directly via your hosting platform's secret management system, as Pydantic Settings prioritizes OS environment variables over file values.

Environment-Specific Behavior

The codebase uses the ENVIRONMENT flag to conditionally enable or disable features based on the deployment context.

API Documentation Visibility

In src/app/core/setup.py, the create_application function disables interactive documentation in production:

if settings.ENVIRONMENT != EnvironmentOption.PRODUCTION:
    # Enable /docs and /redoc

    docs_url = "/docs"
    redoc_url = "/redoc"
else:
    docs_url = None
    redoc_url = None

For staging environments, documentation remains accessible but requires super-user authentication via Depends(get_current_superuser), protecting internal endpoints from public access while allowing developer debugging.

Admin Interface Security

The admin UI enforces HTTPS exclusively in production. In src/app/admin/initialize.py, the setup logic reads:

enforce_https=settings.ENVIRONMENT == EnvironmentOption.PRODUCTION

This ensures local developers can test the admin panel without TLS certificates while production deployments maintain strict transport security.

Startup Lifecycle Adjustments

The lifespan_factory in src/app/core/setup.py receives concrete settings subclasses to attach the correct event handlers for database connections, Redis pools, and rate-limiting backends based on the current environment's resource configuration.

Practical Configuration Examples

Local Development

Create a .env file in the project root with local credentials:

ENVIRONMENT=local
APP_NAME="FastAPI Boilerplate – Local"
POSTGRES_SERVER=localhost
POSTGRES_PORT=5432
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=postgres
REDIS_CACHE_HOST=localhost
REDIS_QUEUE_HOST=localhost
REDIS_RATE_LIMIT_HOST=localhost

Run with uvicorn src.app.main:app --reload. API documentation is publicly available at /docs, and HTTPS enforcement is disabled.

Staging Deployment

ENVIRONMENT=staging
APP_NAME="FastAPI Boilerplate – Staging"
POSTGRES_SERVER=staging-db.example.com
POSTGRES_USER=staging_user
POSTGRES_PASSWORD=staging_pass
POSTGRES_DB=staging_db
REDIS_CACHE_HOST=staging-redis.example.com
REDIS_QUEUE_HOST=staging-redis-queue.example.com
REDIS_RATE_LIMIT_HOST=staging-redis-rate.example.com

In this mode:

  • Documentation requires super-user authentication
  • Admin UI allows HTTP connections
  • All data services point to staging infrastructure

Production Deployment

ENVIRONMENT=production
APP_NAME="FastAPI Boilerplate"
POSTGRES_SERVER=prod-db.example.com
POSTGRES_USER=prod_user
POSTGRES_PASSWORD=prod_secure_pass
POSTGRES_DB=prod_db
REDIS_CACHE_HOST=prod-redis.example.com
REDIS_QUEUE_HOST=prod-redis-queue.example.com
REDIS_RATE_LIMIT_HOST=prod-redis-rate.example.com

Production specifics include:

  • Interactive API documentation is completely disabled (docs_url=None, redoc_url=None)
  • Admin UI forces HTTPS connections
  • Health endpoints report production status for monitoring systems

Extending the Configuration

To add new environment-specific variables, define them in a BaseSettings subclass or directly in AppSettings:

class AppSettings(BaseSettings):
    APP_NAME: str = "FastAPI app"
    SENTRY_DSN: str | None = None
    FEATURE_FLAG_V2: bool = False

These fields automatically become available via settings.SENTRY_DSN and can be set per-environment in your .env files:


# .env.production

SENTRY_DSN=https://...
FEATURE_FLAG_V2=true

Summary

  • Centralize configuration in src/app/core/config.py using Pydantic's BaseSettings to manage environment-specific configurations with type safety.
  • Use the EnvironmentOption enum to represent local, staging, and production states, preventing invalid environment strings.
  • Control feature visibility by checking settings.ENVIRONMENT in src/app/core/setup.py to disable docs in production and protect them in staging.
  • Enforce security policies such as HTTPS-only admin access based on the environment flag in src/app/admin/initialize.py.
  • Maintain separate .env files for each deployment target or inject variables via your platform's secret management to switch contexts without code changes.

Frequently Asked Questions

How does the FastAPI boilerplate determine which environment it is running in?

The application reads the ENVIRONMENT variable from the operating system environment or the .env file, validates it against the EnvironmentOption enum in src/app/core/config.py, and stores it in the global settings object. This value is then referenced throughout the codebase to adjust behavior.

Can I use multiple .env files for different environments?

While the boilerplate defaults to loading a single .env file from the project root, you can maintain separate files (e.g., .env.staging, .env.prod) and copy or symlink the appropriate file to .env during deployment. Alternatively, set variables directly in your hosting platform's environment, as Pydantic Settings prioritizes OS environment variables over file-based values.

Why is the API documentation disabled in production?

According to the source code in src/app/core/setup.py, interactive documentation endpoints (/docs and /redoc) are disabled in production to reduce the attack surface and prevent exposing internal API schemas to the public internet. In staging environments, documentation remains available but requires super-user authentication.

How do I add a new configuration variable that changes per environment?

Define the variable in a BaseSettings subclass within src/app/core/config.py (such as AppSettings), specifying a type and default value. The variable will automatically be available via the global settings object and can be overridden per environment by setting it in the appropriate .env file or deployment platform.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →