Safeguard
Security Guides•

Where should FastAPI secrets live: env vars, .env or a secrets dir?

Read secrets from environment variables or a mounted secrets directory with pydantic settings. Keep .env files out of git and images. Options compared.

Safeguard Security Team
4 min read

Put secrets outside your code. FastAPI's docs recommend environment variables read through a pydantic Settings class, with an optional .env file for development. In containers, pydantic settings can also read each secret from a file in a secrets directory such as /run/secrets. Never commit .env files or bake them into images.

What the FastAPI docs say

The FastAPI settings page opens by noting that applications often need external configuration such as secret keys, database credentials and email service credentials, many of which are sensitive. For that reason it is common to provide them in environment variables read by the application. An environment variable lives outside the Python code, in the operating system.

It then shows a dotenv file, commonly named .env, which pydantic can read through an external library, and tells you to configure env_file inside the Settings class. It also shows creating the settings once with lru_cache, so the file is not re-read on every request.

Three sources compared

SourceGood forWatch out for
Environment variablesProduction, CI, containersVisible to processes and sometimes in crash dumps or debug pages
.env fileLocal developmentCommitted to git, copied into images, shared in chat
Secrets directoryDocker or orchestrator mounted secretsFile permissions, missing mounts

Pydantic Settings documents the third option. In its Docker secrets section, you define the Settings class with a secrets directory such as /run/secrets, and each file in it provides a field value. The docs say a missing secrets directory is ignored with a warning, which is worth knowing: a misconfigured mount may not fail loudly. Check with a startup test that required secrets are present.

Typing secrets

Pydantic offers SecretStr, which its own secrets examples use for fields like keys and passwords. Declaring those fields with that type signals intent and helps avoid printing the value by accident. Read the real value only at the point of use.

from pydantic import SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_file=".env", secrets_dir="/run/secrets")
    database_password: SecretStr

Priority and surprises

Pydantic Settings supports multiple sources and lets you change their priority with settings_customise_sources, where the first item has the highest priority. That is useful, and also a source of surprises: a stray environment variable on a developer machine can override a file value. Know the order your app uses.

Keep secrets out of the wrong places

  1. Add .env to .gitignore and to .dockerignore, so it never enters the repository or the image build context.
  2. Commit an example file with placeholder values.
  3. Scan the repository history for committed secrets. Removing a file later does not remove it from history, so rotate anything that was committed.
  4. Do not log settings objects. Avoid printing the whole configuration at startup.
  5. Use your platform's secret manager and inject values at deploy time. Pydantic Settings documents sources for several cloud secret managers.
  6. Use different secrets per environment, and rotate on a schedule.

Test the failure mode

Write a startup check that fails fast when a required secret is missing or still equals a placeholder. A service that boots with an empty signing key is worse than one that refuses to boot.

Try it yourself

Click through it at your own pace, or open it full screen. Look at how hardcoded credentials in a codebase are reported.

Quick check

Is a .env file safe in production?

It is a development convenience. In production prefer your platform's secret injection and keep the file out of images and repositories.

What if the secrets directory is missing?

Pydantic Settings ignores a missing directory and shows a warning, so add a startup check that required values exist.

Safeguard's SAST and dependency scanning can flag committed secrets and vulnerable packages. Run a free scan.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.