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
productionstatus 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.pyusing Pydantic'sBaseSettingsto manage environment-specific configurations with type safety. - Use the
EnvironmentOptionenum to represent local, staging, and production states, preventing invalid environment strings. - Control feature visibility by checking
settings.ENVIRONMENTinsrc/app/core/setup.pyto 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →