[{"data":1,"prerenderedAt":1884},["ShallowReactive",2],{"nav":3,"page-\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fsecrets-and-env-files-per-environment\u002F":580,"surround-\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fsecrets-and-env-files-per-environment\u002F":1883},[4,186,386],{"title":5,"path":6,"stem":7,"children":8},"Advanced Pydantic Validation Serialization","\u002Fadvanced-pydantic-validation-serialization","advanced-pydantic-validation-serialization",[9,12,42,66,90,114,150,174],{"title":10,"path":6,"stem":11},"Advanced Pydantic Validation and Serialization","advanced-pydantic-validation-serialization\u002Findex",{"title":13,"path":14,"stem":15,"children":16},"Custom Validators and Field Constraints in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Findex",[17,18,24,30,36],{"title":13,"path":14,"stem":15},{"title":19,"path":20,"stem":21,"children":22},"Before, After and Wrap Validators in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fbefore-after-and-wrap-validators","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fbefore-after-and-wrap-validators\u002Findex",[23],{"title":19,"path":20,"stem":21},{"title":25,"path":26,"stem":27,"children":28},"Creating Reusable Custom Validators in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic\u002Findex",[29],{"title":25,"path":26,"stem":27},{"title":31,"path":32,"stem":33,"children":34},"Cross-Field Validation Patterns in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcross-field-validation-patterns","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcross-field-validation-patterns\u002Findex",[35],{"title":31,"path":32,"stem":33},{"title":37,"path":38,"stem":39,"children":40},"Pydantic v2 Async Custom Validator: What to Do Instead","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fpydantic-v2-async-custom-validator","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fpydantic-v2-async-custom-validator\u002Findex",[41],{"title":37,"path":38,"stem":39},{"title":43,"path":44,"stem":45,"children":46},"JSON Schema Customization in Pydantic and FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Findex",[47,48,54,60],{"title":43,"path":44,"stem":45},{"title":49,"path":50,"stem":51,"children":52},"Customizing OpenAPI Schema Generation in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi\u002Findex",[53],{"title":49,"path":50,"stem":51},{"title":55,"path":56,"stem":57,"children":58},"Discriminated Unions in OpenAPI with Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fdiscriminated-unions-in-openapi","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fdiscriminated-unions-in-openapi\u002Findex",[59],{"title":55,"path":56,"stem":57},{"title":61,"path":62,"stem":63,"children":64},"Examples in the OpenAPI Schema with FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fexamples-in-openapi-schema","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fexamples-in-openapi-schema\u002Findex",[65],{"title":61,"path":62,"stem":63},{"title":67,"path":68,"stem":69,"children":70},"Nested Model Serialization in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Findex",[71,72,78,84],{"title":67,"path":68,"stem":69},{"title":73,"path":74,"stem":75,"children":76},"Excluding Fields Per Endpoint in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fexcluding-fields-per-endpoint","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fexcluding-fields-per-endpoint\u002Findex",[77],{"title":73,"path":74,"stem":75},{"title":79,"path":80,"stem":81,"children":82},"Handling Deeply Nested JSON Models Efficiently","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently\u002Findex",[83],{"title":79,"path":80,"stem":81},{"title":85,"path":86,"stem":87,"children":88},"Self-Referencing and Recursive Models in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fself-referencing-and-recursive-models","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fself-referencing-and-recursive-models\u002Findex",[89],{"title":85,"path":86,"stem":87},{"title":91,"path":92,"stem":93,"children":94},"Performance Optimization for Pydantic Models in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Findex",[95,96,102,108],{"title":91,"path":92,"stem":93},{"title":97,"path":98,"stem":99,"children":100},"model_construct and When to Skip Validation in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fmodel-construct-when-to-skip-validation","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fmodel-construct-when-to-skip-validation\u002Findex",[101],{"title":97,"path":98,"stem":99},{"title":103,"path":104,"stem":105,"children":106},"Pydantic Model Serialization Performance in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fpydantic-model-serialization-performance","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fpydantic-model-serialization-performance\u002Findex",[107],{"title":103,"path":104,"stem":105},{"title":109,"path":110,"stem":111,"children":112},"TypeAdapter for Non-Model Types in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Ftypeadapter-for-non-model-types","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Ftypeadapter-for-non-model-types\u002Findex",[113],{"title":109,"path":110,"stem":111},{"title":115,"path":116,"stem":117,"children":118},"Pydantic V2 Migration Guide for FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Findex",[119,120,126,132,138,144],{"title":115,"path":116,"stem":117},{"title":121,"path":122,"stem":123,"children":124},"Migrate @validator to @field_validator in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrate-validator-to-field-validator","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrate-validator-to-field-validator\u002Findex",[125],{"title":121,"path":122,"stem":123},{"title":127,"path":128,"stem":129,"children":130},"Migrating from Pydantic v1 to v2 Without Breaking APIs","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis\u002Findex",[131],{"title":127,"path":128,"stem":129},{"title":133,"path":134,"stem":135,"children":136},"model_config vs class Config in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmodel-config-vs-class-config","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmodel-config-vs-class-config\u002Findex",[137],{"title":133,"path":134,"stem":135},{"title":139,"path":140,"stem":141,"children":142},"Replacing json_encoders with field_serializer in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Freplacing-json-encoders-with-field-serializer","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Freplacing-json-encoders-with-field-serializer\u002Findex",[143],{"title":139,"path":140,"stem":141},{"title":145,"path":146,"stem":147,"children":148},"Migrating @root_validator to @model_validator in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Froot-validator-to-model-validator","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Froot-validator-to-model-validator\u002Findex",[149],{"title":145,"path":146,"stem":147},{"title":151,"path":152,"stem":153,"children":154},"Request Validation Patterns in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Frequest-validation-patterns","advanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Findex",[155,156,162,168],{"title":151,"path":152,"stem":153},{"title":157,"path":158,"stem":159,"children":160},"Optional vs Nullable Fields in Pydantic and FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Foptional-vs-nullable-fields","advanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Foptional-vs-nullable-fields\u002Findex",[161],{"title":157,"path":158,"stem":159},{"title":163,"path":164,"stem":165,"children":166},"Query, Path and Body Parameter Validation in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Fquery-path-and-body-parameter-validation","advanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Fquery-path-and-body-parameter-validation\u002Findex",[167],{"title":163,"path":164,"stem":165},{"title":169,"path":170,"stem":171,"children":172},"Validating File Uploads and Forms in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Fvalidating-file-uploads-and-forms","advanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Fvalidating-file-uploads-and-forms\u002Findex",[173],{"title":169,"path":170,"stem":171},{"title":175,"path":176,"stem":177,"children":178},"Type Hinting and IDE Integration in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration","advanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Findex",[179,180],{"title":175,"path":176,"stem":177},{"title":181,"path":182,"stem":183,"children":184},"Annotated Dependencies and Reusable Types in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Fannotated-dependencies-and-reusable-types","advanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Fannotated-dependencies-and-reusable-types\u002Findex",[185],{"title":181,"path":182,"stem":183},{"title":187,"path":188,"stem":189,"children":190},"Async Background Tasks Observability","\u002Fasync-background-tasks-observability","async-background-tasks-observability",[191,194,224,254,284,308,338,362],{"title":192,"path":188,"stem":193},"Async, Background Tasks, and Observability in FastAPI","async-background-tasks-observability\u002Findex",{"title":195,"path":196,"stem":197,"children":198},"Async Correctness and Concurrency in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Findex",[199,200,206,212,218],{"title":195,"path":196,"stem":197},{"title":201,"path":202,"stem":203,"children":204},"Concurrent Requests with asyncio.gather in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Fconcurrent-requests-with-asyncio-gather","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Fconcurrent-requests-with-asyncio-gather\u002Findex",[205],{"title":201,"path":202,"stem":203},{"title":207,"path":208,"stem":209,"children":210},"FastAPI async def vs def: Performance and When to Use Each","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance\u002Findex",[211],{"title":207,"path":208,"stem":209},{"title":213,"path":214,"stem":215,"children":216},"Fixing Blocking Calls in Async FastAPI Routes","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffixing-blocking-calls-in-async-routes","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffixing-blocking-calls-in-async-routes\u002Findex",[217],{"title":213,"path":214,"stem":215},{"title":219,"path":220,"stem":221,"children":222},"Running Sync Code in a Threadpool in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Frunning-sync-code-in-a-threadpool","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Frunning-sync-code-in-a-threadpool\u002Findex",[223],{"title":219,"path":220,"stem":221},{"title":225,"path":226,"stem":227,"children":228},"Async Database Sessions in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions","async-background-tasks-observability\u002Fasync-database-sessions\u002Findex",[229,230,236,242,248],{"title":225,"path":226,"stem":227},{"title":231,"path":232,"stem":233,"children":234},"Async SQLAlchemy Session per Request in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Fasync-sqlalchemy-session-per-request","async-background-tasks-observability\u002Fasync-database-sessions\u002Fasync-sqlalchemy-session-per-request\u002Findex",[235],{"title":231,"path":232,"stem":233},{"title":237,"path":238,"stem":239,"children":240},"Fixing asyncpg Connection Pool Exhaustion in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Ffixing-asyncpg-pool-exhaustion","async-background-tasks-observability\u002Fasync-database-sessions\u002Ffixing-asyncpg-pool-exhaustion\u002Findex",[241],{"title":237,"path":238,"stem":239},{"title":243,"path":244,"stem":245,"children":246},"Testing with Async Database Fixtures in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Ftesting-with-async-database-fixtures","async-background-tasks-observability\u002Fasync-database-sessions\u002Ftesting-with-async-database-fixtures\u002Findex",[247],{"title":243,"path":244,"stem":245},{"title":249,"path":250,"stem":251,"children":252},"Transaction Management and Rollback in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Ftransaction-management-and-rollback","async-background-tasks-observability\u002Fasync-database-sessions\u002Ftransaction-management-and-rollback\u002Findex",[253],{"title":249,"path":250,"stem":251},{"title":255,"path":256,"stem":257,"children":258},"Background Task Processing in FastAPI","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing","async-background-tasks-observability\u002Fbackground-task-processing\u002Findex",[259,260,266,272,278],{"title":255,"path":256,"stem":257},{"title":261,"path":262,"stem":263,"children":264},"FastAPI BackgroundTasks vs Celery vs ARQ","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Ffastapi-backgroundtasks-vs-celery-vs-arq","async-background-tasks-observability\u002Fbackground-task-processing\u002Ffastapi-backgroundtasks-vs-celery-vs-arq\u002Findex",[265],{"title":261,"path":262,"stem":263},{"title":267,"path":268,"stem":269,"children":270},"Retry and Idempotency for FastAPI Background Tasks","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Fretry-and-idempotency-for-tasks","async-background-tasks-observability\u002Fbackground-task-processing\u002Fretry-and-idempotency-for-tasks\u002Findex",[271],{"title":267,"path":268,"stem":269},{"title":273,"path":274,"stem":275,"children":276},"Running ARQ Workers with FastAPI","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Frunning-arq-workers-with-fastapi","async-background-tasks-observability\u002Fbackground-task-processing\u002Frunning-arq-workers-with-fastapi\u002Findex",[277],{"title":273,"path":274,"stem":275},{"title":279,"path":280,"stem":281,"children":282},"When FastAPI BackgroundTasks Silently Fails","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Fwhen-backgroundtasks-silently-fails","async-background-tasks-observability\u002Fbackground-task-processing\u002Fwhen-backgroundtasks-silently-fails\u002Findex",[283],{"title":279,"path":280,"stem":281},{"title":285,"path":286,"stem":287,"children":288},"Caching Strategies in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies","async-background-tasks-observability\u002Fcaching-strategies\u002Findex",[289,290,296,302],{"title":285,"path":286,"stem":287},{"title":291,"path":292,"stem":293,"children":294},"Cache Invalidation Patterns in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fcache-invalidation-patterns-in-fastapi","async-background-tasks-observability\u002Fcaching-strategies\u002Fcache-invalidation-patterns-in-fastapi\u002Findex",[295],{"title":291,"path":292,"stem":293},{"title":297,"path":298,"stem":299,"children":300},"Caching Dependency Results in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fcaching-dependency-results","async-background-tasks-observability\u002Fcaching-strategies\u002Fcaching-dependency-results\u002Findex",[301],{"title":297,"path":298,"stem":299},{"title":303,"path":304,"stem":305,"children":306},"Redis Response Caching in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fredis-response-caching-in-fastapi","async-background-tasks-observability\u002Fcaching-strategies\u002Fredis-response-caching-in-fastapi\u002Findex",[307],{"title":303,"path":304,"stem":305},{"title":309,"path":310,"stem":311,"children":312},"Observability and Tracing in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing","async-background-tasks-observability\u002Fobservability-and-tracing\u002Findex",[313,314,320,326,332],{"title":309,"path":310,"stem":311},{"title":315,"path":316,"stem":317,"children":318},"Correlating Logs, Traces and Errors in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fcorrelating-logs-traces-and-errors","async-background-tasks-observability\u002Fobservability-and-tracing\u002Fcorrelating-logs-traces-and-errors\u002Findex",[319],{"title":315,"path":316,"stem":317},{"title":321,"path":322,"stem":323,"children":324},"Instrumenting FastAPI with OpenTelemetry","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry","async-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry\u002Findex",[325],{"title":321,"path":322,"stem":323},{"title":327,"path":328,"stem":329,"children":330},"Prometheus Metrics for FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fprometheus-metrics-for-fastapi","async-background-tasks-observability\u002Fobservability-and-tracing\u002Fprometheus-metrics-for-fastapi\u002Findex",[331],{"title":327,"path":328,"stem":329},{"title":333,"path":334,"stem":335,"children":336},"Structured JSON Logging with Request IDs in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids","async-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids\u002Findex",[337],{"title":333,"path":334,"stem":335},{"title":339,"path":340,"stem":341,"children":342},"Rate Limiting and Throttling in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling","async-background-tasks-observability\u002Frate-limiting-throttling\u002Findex",[343,344,350,356],{"title":339,"path":340,"stem":341},{"title":345,"path":346,"stem":347,"children":348},"FastAPI Rate Limiting with Redis and SlowAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Ffastapi-rate-limiting-with-redis-slowapi","async-background-tasks-observability\u002Frate-limiting-throttling\u002Ffastapi-rate-limiting-with-redis-slowapi\u002Findex",[349],{"title":345,"path":346,"stem":347},{"title":351,"path":352,"stem":353,"children":354},"Per-User Token Bucket Throttling in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Fper-user-token-bucket-throttling","async-background-tasks-observability\u002Frate-limiting-throttling\u002Fper-user-token-bucket-throttling\u002Findex",[355],{"title":351,"path":352,"stem":353},{"title":357,"path":358,"stem":359,"children":360},"Rate Limit Headers and 429 Responses in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Frate-limit-headers-and-429-responses","async-background-tasks-observability\u002Frate-limiting-throttling\u002Frate-limit-headers-and-429-responses\u002Findex",[361],{"title":357,"path":358,"stem":359},{"title":363,"path":364,"stem":365,"children":366},"Testing FastAPI Applications","\u002Fasync-background-tasks-observability\u002Ftesting-fastapi-applications","async-background-tasks-observability\u002Ftesting-fastapi-applications\u002Findex",[367,368,374,380],{"title":363,"path":364,"stem":365},{"title":369,"path":370,"stem":371,"children":372},"Mocking External Services in FastAPI Tests","\u002Fasync-background-tasks-observability\u002Ftesting-fastapi-applications\u002Fmocking-external-services-in-tests","async-background-tasks-observability\u002Ftesting-fastapi-applications\u002Fmocking-external-services-in-tests\u002Findex",[373],{"title":369,"path":370,"stem":371},{"title":375,"path":376,"stem":377,"children":378},"TestClient vs httpx AsyncClient in FastAPI","\u002Fasync-background-tasks-observability\u002Ftesting-fastapi-applications\u002Ftestclient-vs-httpx-asyncclient","async-background-tasks-observability\u002Ftesting-fastapi-applications\u002Ftestclient-vs-httpx-asyncclient\u002Findex",[379],{"title":375,"path":376,"stem":377},{"title":381,"path":382,"stem":383,"children":384},"Testing Async FastAPI Endpoints with pytest-asyncio","\u002Fasync-background-tasks-observability\u002Ftesting-fastapi-applications\u002Ftesting-async-endpoints-with-pytest-asyncio","async-background-tasks-observability\u002Ftesting-fastapi-applications\u002Ftesting-async-endpoints-with-pytest-asyncio\u002Findex",[385],{"title":381,"path":382,"stem":383},{"title":387,"path":388,"stem":389,"children":390},"Core Architecture Routing Patterns","\u002Fcore-architecture-routing-patterns","core-architecture-routing-patterns",[391,394,412,436,472,496,526,556],{"title":392,"path":388,"stem":393},"FastAPI Core Architecture and Routing Patterns","core-architecture-routing-patterns\u002Findex",{"title":395,"path":396,"stem":397,"children":398},"Application Factory Patterns in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Findex",[399,400,406],{"title":395,"path":396,"stem":397},{"title":401,"path":402,"stem":403,"children":404},"FastAPI App Factory Pattern for Testing and Deployment","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment\u002Findex",[405],{"title":401,"path":402,"stem":403},{"title":407,"path":408,"stem":409,"children":410},"Lifespan Events vs Startup and Shutdown in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Flifespan-events-vs-startup-shutdown","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Flifespan-events-vs-startup-shutdown\u002Findex",[411],{"title":407,"path":408,"stem":409},{"title":413,"path":414,"stem":415,"children":416},"Configuration Management in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management","core-architecture-routing-patterns\u002Fconfiguration-management\u002Findex",[417,418,424,430],{"title":413,"path":414,"stem":415},{"title":419,"path":420,"stem":421,"children":422},"Managing Environment Variables with Pydantic Settings","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings\u002Findex",[423],{"title":419,"path":420,"stem":421},{"title":425,"path":426,"stem":427,"children":428},"Pydantic Settings vs Dynaconf vs python-decouple","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fpydantic-settings-vs-dynaconf-vs-python-decouple","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fpydantic-settings-vs-dynaconf-vs-python-decouple\u002Findex",[429],{"title":425,"path":426,"stem":427},{"title":431,"path":432,"stem":433,"children":434},"Secrets and .env Files Per Environment in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fsecrets-and-env-files-per-environment","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fsecrets-and-env-files-per-environment\u002Findex",[435],{"title":431,"path":432,"stem":433},{"title":437,"path":438,"stem":439,"children":440},"Dependency Injection Strategies in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Findex",[441,442,448,454,460,466],{"title":437,"path":438,"stem":439},{"title":443,"path":444,"stem":445,"children":446},"Best Practices for FastAPI Dependency Injection","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection\u002Findex",[447],{"title":443,"path":444,"stem":445},{"title":449,"path":450,"stem":451,"children":452},"Dependency Caching and use_cache in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fdependency-caching-and-use-cache","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fdependency-caching-and-use-cache\u002Findex",[453],{"title":449,"path":450,"stem":451},{"title":455,"path":456,"stem":457,"children":458},"Fixing FastAPI Dependency Injection Circular Imports","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Ffastapi-dependency-injection-circular-import-fix","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Ffastapi-dependency-injection-circular-import-fix\u002Findex",[459],{"title":455,"path":456,"stem":457},{"title":461,"path":462,"stem":463,"children":464},"Overriding Dependencies in FastAPI Tests","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Foverriding-dependencies-in-tests","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Foverriding-dependencies-in-tests\u002Findex",[465],{"title":461,"path":462,"stem":463},{"title":467,"path":468,"stem":469,"children":470},"Yield Dependencies and Cleanup Order in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fyield-dependencies-and-cleanup-order","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fyield-dependencies-and-cleanup-order\u002Findex",[471],{"title":467,"path":468,"stem":469},{"title":473,"path":474,"stem":475,"children":476},"Error Handling and Global Exceptions in FastAPI","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Findex",[477,478,484,490],{"title":473,"path":474,"stem":475},{"title":479,"path":480,"stem":481,"children":482},"Customising Validation Error Responses in FastAPI","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fcustomising-validation-error-responses","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fcustomising-validation-error-responses\u002Findex",[483],{"title":479,"path":480,"stem":481},{"title":485,"path":486,"stem":487,"children":488},"Global Exception Handlers for Consistent API Responses","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses\u002Findex",[489],{"title":485,"path":486,"stem":487},{"title":491,"path":492,"stem":493,"children":494},"HTTPException vs Custom Exception Classes in FastAPI","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fhttpexception-vs-custom-exception-classes","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fhttpexception-vs-custom-exception-classes\u002Findex",[495],{"title":491,"path":492,"stem":493},{"title":497,"path":498,"stem":499,"children":500},"Middleware Implementation in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Findex",[501,502,508,514,520],{"title":497,"path":498,"stem":499},{"title":503,"path":504,"stem":505,"children":506},"CORS Middleware Configuration in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fcors-middleware-configuration","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fcors-middleware-configuration\u002Findex",[507],{"title":503,"path":504,"stem":505},{"title":509,"path":510,"stem":511,"children":512},"Implementing Custom Middleware for Request Tracing","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing\u002Findex",[513],{"title":509,"path":510,"stem":511},{"title":515,"path":516,"stem":517,"children":518},"Middleware Execution Order in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fmiddleware-execution-order","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fmiddleware-execution-order\u002Findex",[519],{"title":515,"path":516,"stem":517},{"title":521,"path":522,"stem":523,"children":524},"Middleware vs Dependencies: When to Use Which","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fmiddleware-vs-dependencies-when-to-use-which","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fmiddleware-vs-dependencies-when-to-use-which\u002Findex",[525],{"title":521,"path":522,"stem":523},{"title":527,"path":528,"stem":529,"children":530},"Modular Router Organization in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Findex",[531,532,538,544,550],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"APIRouter Prefix vs Sub-Application Mounting in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fapirouter-prefix-vs-sub-application-mounting","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fapirouter-prefix-vs-sub-application-mounting\u002Findex",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541,"children":542},"How to Structure Large FastAPI Projects for Scale","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale\u002Findex",[543],{"title":539,"path":540,"stem":541},{"title":545,"path":546,"stem":547,"children":548},"Router Tags and OpenAPI Grouping in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Frouter-tags-and-openapi-grouping","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Frouter-tags-and-openapi-grouping\u002Findex",[549],{"title":545,"path":546,"stem":547},{"title":551,"path":552,"stem":553,"children":554},"Versioning APIs with FastAPI Routers","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fversioning-apis-with-routers","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fversioning-apis-with-routers\u002Findex",[555],{"title":551,"path":552,"stem":553},{"title":557,"path":558,"stem":559,"children":560},"The FastAPI Request\u002FResponse Lifecycle","\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle","core-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Findex",[561,562,568,574],{"title":557,"path":558,"stem":559},{"title":563,"path":564,"stem":565,"children":566},"How a Request Flows Through FastAPI","\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fhow-a-request-flows-through-fastapi","core-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fhow-a-request-flows-through-fastapi\u002Findex",[567],{"title":563,"path":564,"stem":565},{"title":569,"path":570,"stem":571,"children":572},"Response Model and Serialization Order","\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fresponse-model-and-serialization-order","core-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fresponse-model-and-serialization-order\u002Findex",[573],{"title":569,"path":570,"stem":571},{"title":575,"path":576,"stem":577,"children":578},"Streaming and File Responses in FastAPI","\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fstreaming-and-file-responses","core-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fstreaming-and-file-responses\u002Findex",[579],{"title":575,"path":576,"stem":577},{"id":581,"title":431,"body":582,"dateModified":1853,"datePublished":1853,"description":1854,"extension":1855,"faq":1856,"howto":1867,"meta":1868,"navigation":896,"path":432,"seo":1880,"stem":433,"type":1881,"__hash__":1882},"content\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fsecrets-and-env-files-per-environment\u002Findex.md",{"type":583,"value":584,"toc":1844},"minimark",[585,589,596,646,655,660,663,674,759,763,773,779,808,828,832,841,1306,1312,1376,1382,1385,1392,1438,1444,1448,1451,1454,1547,1550,1642,1656,1660,1673,1683,1704,1710,1716,1720,1736,1746,1760,1780,1802,1806,1840],[586,587,431],"h1",{"id":588},"secrets-and-env-files-per-environment-in-fastapi",[590,591,592],"p",{},[593,594,595],"strong",{},"Key takeaways:",[597,598,599,608,614,628,643],"ul",{},[600,601,602,603,607],"li",{},"pydantic-settings resolves in a fixed order: init arguments, environment, ",[604,605,606],"code",{},".env",", secrets directory, defaults.",[600,609,610,611,613],{},"Put non-sensitive per-environment values in a committed ",[604,612,606],{}," file; inject secrets as environment variables.",[600,615,616,619,620,623,624,627],{},[604,617,618],{},"SecretStr"," masks the value in ",[604,621,622],{},"repr"," and ",[604,625,626],{},"str",", so a stray log line prints asterisks.",[600,629,630,631,633,634,638,639,642],{},"Select the ",[604,632,606],{}," path from a bootstrap variable ",[635,636,637],"em",{},"before"," constructing ",[604,640,641],{},"Settings",".",[600,644,645],{},"Log the resolved settings at startup — masked — so misnamed keys fail loudly instead of silently defaulting.",[590,647,648,649,654],{},"This guide extends ",[650,651,653],"a",{"href":652},"\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002F","Configuration Management",", which introduces settings as a typed object; here the focus is the layering between environments and what happens to the credentials in the middle of it.",[656,657,659],"h2",{"id":658},"the-problem-this-solves","The Problem This Solves",[590,661,662],{},"Staging needs a different database URL from production, and both need a password that must never appear in the repository, in a log line, or in a Sentry event. Meanwhile a developer running locally wants everything to work with no configuration at all.",[590,664,665,666,669,670,673],{},"Those three requirements pull in different directions, and the usual failure is to resolve the tension with ",[604,667,668],{},"os.environ.get(\"DATABASE_URL\", \"postgresql:\u002F\u002Flocalhost\u002Fapp\")"," scattered across the codebase. That gives you no type checking, no single place to see what the app needs, defaults that silently mask a missing variable in production, and a password that a ",[604,671,672],{},"logging.info(f\"config: {config}\")"," will happily print.",[675,676,682,686,690,698,702,708,713,722,728,731,735,740,745,748,752,755],"svg",{"viewBox":677,"role":678,"ariaLabel":679,"xmlns":680,"style":681},"0 0 720 340","img","The five settings sources in priority order, highest at the top","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;height:auto;max-width:720px;margin:2rem 0",[683,684,685],"title",{},"Settings source priority in pydantic-settings",[687,688,689],"desc",{},"Five stacked layers showing that arguments passed to Settings win over process environment variables, which win over the dotenv file, which wins over the secrets directory, which wins over the class field defaults.",[691,692],"line",{"x1":693,"y1":694,"x2":693,"y2":695,"stroke":696,"strokeWidth":697},"96","300","40","#00796B","2",[699,700],"polygon",{"points":701,"fill":696},"91,40 96,28 101,40",[703,704,707],"text",{"x":693,"y":705,"style":706},"20","text-anchor:middle;fill:#00796B;font:700 12px sans-serif","wins",[703,709,712],{"x":693,"y":710,"style":711},"322","text-anchor:middle;fill:currentColor;font:400 12px sans-serif","falls back",[714,715],"rect",{"x":716,"y":717,"width":718,"height":719,"rx":720,"fill":721,"stroke":696,"strokeWidth":697},"170","30","400","44","8","none",[703,723,727],{"x":724,"y":725,"style":726},"370","58","text-anchor:middle;fill:#00796B;font:600 13px sans-serif","1 · Settings(database_url=...) arguments",[714,729],{"x":716,"y":730,"width":718,"height":719,"rx":720,"fill":721,"stroke":696,"strokeWidth":697},"88",[703,732,734],{"x":724,"y":733,"style":726},"116","2 · process environment — injected secrets",[714,736],{"x":716,"y":737,"width":718,"height":719,"rx":720,"fill":721,"stroke":738,"strokeWidth":739},"146","currentColor","1.5",[703,741,744],{"x":724,"y":742,"style":743},"174","text-anchor:middle;fill:currentColor;font:600 13px sans-serif","3 · .env file — per-environment values",[714,746],{"x":716,"y":747,"width":718,"height":719,"rx":720,"fill":721,"stroke":738,"strokeWidth":739},"204",[703,749,751],{"x":724,"y":750,"style":743},"232","4 · secrets directory — mounted files",[714,753],{"x":716,"y":754,"width":718,"height":719,"rx":720,"fill":721,"stroke":738,"strokeWidth":739},"262",[703,756,758],{"x":724,"y":757,"style":743},"290","5 · class defaults — local development",[656,760,762],{"id":761},"why-it-happens","Why It Happens",[590,764,765,768,769,772],{},[604,766,767],{},"BaseSettings"," is a normal Pydantic model with a customised initialisation step. Before validation runs, it asks each configured ",[635,770,771],{},"settings source"," for a dictionary of values and merges them, with earlier sources taking precedence. The default chain is, highest priority first: arguments passed to the constructor, then the process environment, then the dotenv file, then the secrets directory, then the model's own field defaults.",[590,774,775,776,778],{},"That ordering is the whole design. It means a ",[604,777,606],{}," file can carry the values that describe an environment while the orchestrator injects the values that must not be written down — and the injected ones win without anyone having to remember to delete a line from the file.",[590,780,781,784,785,788,789,792,793,796,797,800,801,804,805,807],{},[604,782,783],{},"SettingsConfigDict"," configures those sources. ",[604,786,787],{},"env_prefix"," namespaces the environment lookups so your ",[604,790,791],{},"database_url"," reads ",[604,794,795],{},"APP_DATABASE_URL"," and cannot collide with something else on the host. ",[604,798,799],{},"env_file"," names the dotenv path. ",[604,802,803],{},"extra=\"ignore\""," stops an unrelated variable in the file from raising a validation error — worth setting, because a shared ",[604,806,606],{}," usually carries keys for more than one process.",[590,809,810,812,813,623,816,819,820,823,824,827],{},[604,811,618],{}," is a different mechanism. It is a wrapper type whose ",[604,814,815],{},"__repr__",[604,817,818],{},"__str__"," return a fixed mask instead of the value. Since almost every accidental disclosure goes through one of those two methods — an f-string in a log call, a ",[604,821,822],{},"repr()"," in a traceback frame, a settings object dumped into an error report — wrapping the field converts a class of accidents into a harmless string of asterisks. Reading the real value requires calling ",[604,825,826],{},"get_secret_value()",", which is greppable and reviewable.",[656,829,831],{"id":830},"the-fix","The Fix",[590,833,834,835,837,838,840],{},"Build the settings class once, choose the dotenv path from a bootstrap variable, and wrap every credential in ",[604,836,618],{},". This example creates the ",[604,839,606],{}," file it reads so the transcript below is produced by genuinely resolving all three layers:",[842,843,848],"pre",{"className":844,"code":845,"language":846,"meta":847,"style":847},"language-python shiki shiki-themes github-light-high-contrast","\"\"\"Resolve settings through three layers — class defaults, .env file, process environment.\"\"\"\nimport os\nimport tempfile\nfrom pathlib import Path\n\nfrom fastapi import FastAPI\nfrom pydantic import Field, SecretStr\nfrom pydantic_settings import BaseSettings, SettingsConfigDict\n\nENV_DIR = Path(tempfile.mkdtemp(prefix=\"cfg-layered-\"))\nENV_FILE = ENV_DIR \u002F \".env.staging\"\nENV_FILE.write_text(\n    \"APP_ENVIRONMENT=staging\\n\"\n    \"APP_DATABASE_URL=postgresql:\u002F\u002Fapp@db.staging.internal\u002Fapp\\n\"\n    \"APP_DATABASE_PASSWORD=env-file-password\\n\"\n    \"APP_REQUEST_TIMEOUT_S=8.0\\n\"\n)\n\n# The orchestrator's injected secret. It must win over the .env file.\nos.environ[\"APP_DATABASE_PASSWORD\"] = \"injected-by-the-orchestrator\"\n\n\nclass Settings(BaseSettings):\n    \"\"\"Layer 1 is these defaults; the .env file overrides them; the environment overrides that.\"\"\"\n\n    model_config = SettingsConfigDict(\n        env_prefix=\"APP_\",\n        env_file=ENV_FILE,\n        env_file_encoding=\"utf-8\",\n        extra=\"ignore\",\n        frozen=True,\n    )\n\n    environment: str = \"local\"\n    database_url: str = \"postgresql:\u002F\u002Fapp@localhost\u002Fapp\"\n    database_password: SecretStr = SecretStr(\"change-me\")\n    request_timeout_s: float = 3.0\n    log_level: str = Field(default=\"INFO\", description=\"Never set to DEBUG in production.\")\n\n\nsettings = Settings()\n","python","",[604,849,850,858,869,877,891,898,911,924,937,942,968,985,993,1005,1015,1025,1035,1041,1046,1053,1070,1075,1080,1097,1103,1108,1119,1133,1145,1158,1171,1184,1190,1195,1208,1221,1237,1251,1285,1290,1295],{"__ignoreMap":847},[851,852,854],"span",{"class":691,"line":853},1,[851,855,857],{"class":856},"sYEJz","\"\"\"Resolve settings through three layers — class defaults, .env file, process environment.\"\"\"\n",[851,859,861,865],{"class":691,"line":860},2,[851,862,864],{"class":863},"sTJeM","import",[851,866,868],{"class":867},"sigWx"," os\n",[851,870,872,874],{"class":691,"line":871},3,[851,873,864],{"class":863},[851,875,876],{"class":867}," tempfile\n",[851,878,880,883,886,888],{"class":691,"line":879},4,[851,881,882],{"class":863},"from",[851,884,885],{"class":867}," pathlib ",[851,887,864],{"class":863},[851,889,890],{"class":867}," Path\n",[851,892,894],{"class":691,"line":893},5,[851,895,897],{"emptyLinePlaceholder":896},true,"\n",[851,899,901,903,906,908],{"class":691,"line":900},6,[851,902,882],{"class":863},[851,904,905],{"class":867}," fastapi ",[851,907,864],{"class":863},[851,909,910],{"class":867}," FastAPI\n",[851,912,914,916,919,921],{"class":691,"line":913},7,[851,915,882],{"class":863},[851,917,918],{"class":867}," pydantic ",[851,920,864],{"class":863},[851,922,923],{"class":867}," Field, SecretStr\n",[851,925,927,929,932,934],{"class":691,"line":926},8,[851,928,882],{"class":863},[851,930,931],{"class":867}," pydantic_settings ",[851,933,864],{"class":863},[851,935,936],{"class":867}," BaseSettings, SettingsConfigDict\n",[851,938,940],{"class":691,"line":939},9,[851,941,897],{"emptyLinePlaceholder":896},[851,943,945,949,952,955,959,962,965],{"class":691,"line":944},10,[851,946,948],{"class":947},"sacAq","ENV_DIR",[851,950,951],{"class":863}," =",[851,953,954],{"class":867}," Path(tempfile.mkdtemp(",[851,956,958],{"class":957},"sV4o_","prefix",[851,960,961],{"class":863},"=",[851,963,964],{"class":856},"\"cfg-layered-\"",[851,966,967],{"class":867},"))\n",[851,969,971,974,976,979,982],{"class":691,"line":970},11,[851,972,973],{"class":947},"ENV_FILE",[851,975,951],{"class":863},[851,977,978],{"class":947}," ENV_DIR",[851,980,981],{"class":863}," \u002F",[851,983,984],{"class":856}," \".env.staging\"\n",[851,986,988,990],{"class":691,"line":987},12,[851,989,973],{"class":947},[851,991,992],{"class":867},".write_text(\n",[851,994,996,999,1002],{"class":691,"line":995},13,[851,997,998],{"class":856},"    \"APP_ENVIRONMENT=staging",[851,1000,1001],{"class":863},"\\n",[851,1003,1004],{"class":856},"\"\n",[851,1006,1008,1011,1013],{"class":691,"line":1007},14,[851,1009,1010],{"class":856},"    \"APP_DATABASE_URL=postgresql:\u002F\u002Fapp@db.staging.internal\u002Fapp",[851,1012,1001],{"class":863},[851,1014,1004],{"class":856},[851,1016,1018,1021,1023],{"class":691,"line":1017},15,[851,1019,1020],{"class":856},"    \"APP_DATABASE_PASSWORD=env-file-password",[851,1022,1001],{"class":863},[851,1024,1004],{"class":856},[851,1026,1028,1031,1033],{"class":691,"line":1027},16,[851,1029,1030],{"class":856},"    \"APP_REQUEST_TIMEOUT_S=8.0",[851,1032,1001],{"class":863},[851,1034,1004],{"class":856},[851,1036,1038],{"class":691,"line":1037},17,[851,1039,1040],{"class":867},")\n",[851,1042,1044],{"class":691,"line":1043},18,[851,1045,897],{"emptyLinePlaceholder":896},[851,1047,1049],{"class":691,"line":1048},19,[851,1050,1052],{"class":1051},"sFeEa","# The orchestrator's injected secret. It must win over the .env file.\n",[851,1054,1056,1059,1062,1065,1067],{"class":691,"line":1055},20,[851,1057,1058],{"class":867},"os.environ[",[851,1060,1061],{"class":856},"\"APP_DATABASE_PASSWORD\"",[851,1063,1064],{"class":867},"] ",[851,1066,961],{"class":863},[851,1068,1069],{"class":856}," \"injected-by-the-orchestrator\"\n",[851,1071,1073],{"class":691,"line":1072},21,[851,1074,897],{"emptyLinePlaceholder":896},[851,1076,1078],{"class":691,"line":1077},22,[851,1079,897],{"emptyLinePlaceholder":896},[851,1081,1083,1086,1089,1092,1094],{"class":691,"line":1082},23,[851,1084,1085],{"class":863},"class",[851,1087,1088],{"class":957}," Settings",[851,1090,1091],{"class":867},"(",[851,1093,767],{"class":947},[851,1095,1096],{"class":867},"):\n",[851,1098,1100],{"class":691,"line":1099},24,[851,1101,1102],{"class":856},"    \"\"\"Layer 1 is these defaults; the .env file overrides them; the environment overrides that.\"\"\"\n",[851,1104,1106],{"class":691,"line":1105},25,[851,1107,897],{"emptyLinePlaceholder":896},[851,1109,1111,1114,1116],{"class":691,"line":1110},26,[851,1112,1113],{"class":867},"    model_config ",[851,1115,961],{"class":863},[851,1117,1118],{"class":867}," SettingsConfigDict(\n",[851,1120,1122,1125,1127,1130],{"class":691,"line":1121},27,[851,1123,1124],{"class":957},"        env_prefix",[851,1126,961],{"class":863},[851,1128,1129],{"class":856},"\"APP_\"",[851,1131,1132],{"class":867},",\n",[851,1134,1136,1139,1141,1143],{"class":691,"line":1135},28,[851,1137,1138],{"class":957},"        env_file",[851,1140,961],{"class":863},[851,1142,973],{"class":947},[851,1144,1132],{"class":867},[851,1146,1148,1151,1153,1156],{"class":691,"line":1147},29,[851,1149,1150],{"class":957},"        env_file_encoding",[851,1152,961],{"class":863},[851,1154,1155],{"class":856},"\"utf-8\"",[851,1157,1132],{"class":867},[851,1159,1161,1164,1166,1169],{"class":691,"line":1160},30,[851,1162,1163],{"class":957},"        extra",[851,1165,961],{"class":863},[851,1167,1168],{"class":856},"\"ignore\"",[851,1170,1132],{"class":867},[851,1172,1174,1177,1179,1182],{"class":691,"line":1173},31,[851,1175,1176],{"class":957},"        frozen",[851,1178,961],{"class":863},[851,1180,1181],{"class":947},"True",[851,1183,1132],{"class":867},[851,1185,1187],{"class":691,"line":1186},32,[851,1188,1189],{"class":867},"    )\n",[851,1191,1193],{"class":691,"line":1192},33,[851,1194,897],{"emptyLinePlaceholder":896},[851,1196,1198,1201,1203,1205],{"class":691,"line":1197},34,[851,1199,1200],{"class":867},"    environment: ",[851,1202,626],{"class":947},[851,1204,951],{"class":863},[851,1206,1207],{"class":856}," \"local\"\n",[851,1209,1211,1214,1216,1218],{"class":691,"line":1210},35,[851,1212,1213],{"class":867},"    database_url: ",[851,1215,626],{"class":947},[851,1217,951],{"class":863},[851,1219,1220],{"class":856}," \"postgresql:\u002F\u002Fapp@localhost\u002Fapp\"\n",[851,1222,1224,1227,1229,1232,1235],{"class":691,"line":1223},36,[851,1225,1226],{"class":867},"    database_password: SecretStr ",[851,1228,961],{"class":863},[851,1230,1231],{"class":867}," SecretStr(",[851,1233,1234],{"class":856},"\"change-me\"",[851,1236,1040],{"class":867},[851,1238,1240,1243,1246,1248],{"class":691,"line":1239},37,[851,1241,1242],{"class":867},"    request_timeout_s: ",[851,1244,1245],{"class":947},"float",[851,1247,951],{"class":863},[851,1249,1250],{"class":947}," 3.0\n",[851,1252,1254,1257,1259,1261,1264,1267,1269,1272,1275,1278,1280,1283],{"class":691,"line":1253},38,[851,1255,1256],{"class":867},"    log_level: ",[851,1258,626],{"class":947},[851,1260,951],{"class":863},[851,1262,1263],{"class":867}," Field(",[851,1265,1266],{"class":957},"default",[851,1268,961],{"class":863},[851,1270,1271],{"class":856},"\"INFO\"",[851,1273,1274],{"class":867},", ",[851,1276,1277],{"class":957},"description",[851,1279,961],{"class":863},[851,1281,1282],{"class":856},"\"Never set to DEBUG in production.\"",[851,1284,1040],{"class":867},[851,1286,1288],{"class":691,"line":1287},39,[851,1289,897],{"emptyLinePlaceholder":896},[851,1291,1293],{"class":691,"line":1292},40,[851,1294,897],{"emptyLinePlaceholder":896},[851,1296,1298,1301,1303],{"class":691,"line":1297},41,[851,1299,1300],{"class":867},"settings ",[851,1302,961],{"class":863},[851,1304,1305],{"class":867}," Settings()\n",[590,1307,1308,1309,1311],{},"In a real service the ",[604,1310,606],{}," path comes from a bootstrap variable rather than a temporary directory, and it is the one value you read straight from the environment:",[842,1313,1315],{"className":844,"code":1314,"language":846,"meta":847,"style":847},"# Choose the file BEFORE the class is defined — the class cannot know its own environment.\nENV_NAME = os.environ.get(\"APP_ENV\", \"local\")\nENV_FILE = Path(__file__).parent \u002F f\".env.{ENV_NAME}\"\n",[604,1316,1317,1322,1342],{"__ignoreMap":847},[851,1318,1319],{"class":691,"line":853},[851,1320,1321],{"class":1051},"# Choose the file BEFORE the class is defined — the class cannot know its own environment.\n",[851,1323,1324,1327,1329,1332,1335,1337,1340],{"class":691,"line":860},[851,1325,1326],{"class":947},"ENV_NAME",[851,1328,951],{"class":863},[851,1330,1331],{"class":867}," os.environ.get(",[851,1333,1334],{"class":856},"\"APP_ENV\"",[851,1336,1274],{"class":867},[851,1338,1339],{"class":856},"\"local\"",[851,1341,1040],{"class":867},[851,1343,1344,1346,1348,1351,1354,1357,1360,1363,1366,1369,1371,1374],{"class":691,"line":871},[851,1345,973],{"class":947},[851,1347,951],{"class":863},[851,1349,1350],{"class":867}," Path(",[851,1352,1353],{"class":947},"__file__",[851,1355,1356],{"class":867},").parent ",[851,1358,1359],{"class":863},"\u002F",[851,1361,1362],{"class":863}," f",[851,1364,1365],{"class":856},"\".env.",[851,1367,1368],{"class":863},"{",[851,1370,1326],{"class":947},[851,1372,1373],{"class":863},"}",[851,1375,1004],{"class":856},[590,1377,1378,1381],{},[604,1379,1380],{},"frozen=True"," is worth the two seconds it costs. Settings that can be mutated at runtime turn \"what was the timeout in production at 04:00\" into an unanswerable question.",[590,1383,1384],{},"Here is the resolved configuration and the leak check, from a real run:",[842,1386,1390],{"className":1387,"code":1389,"language":703,"meta":847},[1388],"language-text","$ GET \u002Fconfig\n200 OK\n{\n  \"environment\": \"staging\",\n  \"database_url\": \"postgresql:\u002F\u002Fapp@db.staging.internal\u002Fapp\",\n  \"request_timeout_s\": 8.0,\n  \"log_level\": \"INFO\",\n  \"database_password\": \"**********\",\n  \"resolved_from\": {\n    \"environment\": \"the .env file (default was 'local')\",\n    \"database_password\": \"the process environment (the .env value lost)\",\n    \"log_level\": \"the class default (nothing else set it)\"\n  }\n}\n\n$ GET \u002Fconfig\u002Fleak-check\n200 OK\n{\n  \"repr_of_settings\": \"Settings(environment='staging', database_url='postgresql:\u002F\u002Fapp@db.staging.internal\u002Fapp', database_password=SecretStr('**********'), request_timeout_s=8.0, log_level='INFO')\",\n  \"repr_of_secret\": \"SecretStr('**********')\",\n  \"str_of_secret\": \"**********\",\n  \"explicit_reveal\": \"injected-by-the-orchestrator\"\n}\n",[604,1391,1389],{"__ignoreMap":847},[590,1393,1394,1395,623,1398,1400,1401,1403,1404,1407,1408,1411,1412,1415,1416,1419,1420,1423,1424,1427,1428,1430,1431,1433,1434,1437],{},"All three layers are visible in that first response. ",[604,1396,1397],{},"environment",[604,1399,791],{}," came from the ",[604,1402,606],{}," file, overriding the class defaults. ",[604,1405,1406],{},"request_timeout_s"," came from the file as the string ",[604,1409,1410],{},"\"8.0\""," and arrived as the float ",[604,1413,1414],{},"8.0",", because settings sources return strings and Pydantic coerces them against the annotation. ",[604,1417,1418],{},"log_level"," fell all the way through to its default because nothing set it. And ",[604,1421,1422],{},"database_password"," shows ",[604,1425,1426],{},"injected-by-the-orchestrator"," only when ",[604,1429,826],{}," is called explicitly — the ",[604,1432,606],{}," file's ",[604,1435,1436],{},"env-file-password"," lost, exactly as the priority order promises.",[590,1439,1440,1441,1443],{},"The second response is the part to internalise. ",[604,1442,822],{}," of the entire settings object — the single most common way a configuration leaks into a log aggregator — prints the database URL in full and the password as ten asterisks.",[656,1445,1447],{"id":1446},"verification","Verification",[590,1449,1450],{},"Two checks belong in CI, and one belongs at startup.",[590,1452,1453],{},"In CI, assert the precedence rather than assuming it, especially after a pydantic-settings upgrade:",[842,1455,1457],{"className":844,"code":1456,"language":846,"meta":847,"style":847},"def test_environment_beats_env_file(monkeypatch, tmp_path):\n    env_file = tmp_path \u002F \".env\"\n    env_file.write_text(\"APP_DATABASE_PASSWORD=from-file\\n\")\n    monkeypatch.setenv(\"APP_DATABASE_PASSWORD\", \"from-environment\")\n    s = Settings(_env_file=env_file)\n    assert s.database_password.get_secret_value() == \"from-environment\"\n",[604,1458,1459,1471,1486,1501,1515,1533],{"__ignoreMap":847},[851,1460,1461,1464,1468],{"class":691,"line":853},[851,1462,1463],{"class":863},"def",[851,1465,1467],{"class":1466},"s3dhs"," test_environment_beats_env_file",[851,1469,1470],{"class":867},"(monkeypatch, tmp_path):\n",[851,1472,1473,1476,1478,1481,1483],{"class":691,"line":860},[851,1474,1475],{"class":867},"    env_file ",[851,1477,961],{"class":863},[851,1479,1480],{"class":867}," tmp_path ",[851,1482,1359],{"class":863},[851,1484,1485],{"class":856}," \".env\"\n",[851,1487,1488,1491,1494,1496,1499],{"class":691,"line":871},[851,1489,1490],{"class":867},"    env_file.write_text(",[851,1492,1493],{"class":856},"\"APP_DATABASE_PASSWORD=from-file",[851,1495,1001],{"class":863},[851,1497,1498],{"class":856},"\"",[851,1500,1040],{"class":867},[851,1502,1503,1506,1508,1510,1513],{"class":691,"line":879},[851,1504,1505],{"class":867},"    monkeypatch.setenv(",[851,1507,1061],{"class":856},[851,1509,1274],{"class":867},[851,1511,1512],{"class":856},"\"from-environment\"",[851,1514,1040],{"class":867},[851,1516,1517,1520,1522,1525,1528,1530],{"class":691,"line":893},[851,1518,1519],{"class":867},"    s ",[851,1521,961],{"class":863},[851,1523,1524],{"class":867}," Settings(",[851,1526,1527],{"class":957},"_env_file",[851,1529,961],{"class":863},[851,1531,1532],{"class":867},"env_file)\n",[851,1534,1535,1538,1541,1544],{"class":691,"line":900},[851,1536,1537],{"class":863},"    assert",[851,1539,1540],{"class":867}," s.database_password.get_secret_value() ",[851,1542,1543],{"class":863},"==",[851,1545,1546],{"class":856}," \"from-environment\"\n",[590,1548,1549],{},"Also assert that production cannot boot with a placeholder, which turns a missing injected secret from a runtime incident into a failed deploy:",[842,1551,1553],{"className":844,"code":1552,"language":846,"meta":847,"style":847},"@model_validator(mode=\"after\")\ndef reject_placeholder_secrets(self) -> \"Settings\":\n    if self.environment == \"production\" and self.database_password.get_secret_value() == \"change-me\":\n        raise ValueError(\"APP_DATABASE_PASSWORD was not injected in production\")\n    return self\n",[604,1554,1555,1572,1588,1619,1634],{"__ignoreMap":847},[851,1556,1557,1560,1562,1565,1567,1570],{"class":691,"line":853},[851,1558,1559],{"class":1466},"@model_validator",[851,1561,1091],{"class":867},[851,1563,1564],{"class":957},"mode",[851,1566,961],{"class":863},[851,1568,1569],{"class":856},"\"after\"",[851,1571,1040],{"class":867},[851,1573,1574,1576,1579,1582,1585],{"class":691,"line":860},[851,1575,1463],{"class":863},[851,1577,1578],{"class":1466}," reject_placeholder_secrets",[851,1580,1581],{"class":867},"(self) -> ",[851,1583,1584],{"class":856},"\"Settings\"",[851,1586,1587],{"class":867},":\n",[851,1589,1590,1593,1596,1599,1601,1604,1607,1609,1612,1614,1617],{"class":691,"line":871},[851,1591,1592],{"class":863},"    if",[851,1594,1595],{"class":947}," self",[851,1597,1598],{"class":867},".environment ",[851,1600,1543],{"class":863},[851,1602,1603],{"class":856}," \"production\"",[851,1605,1606],{"class":863}," and",[851,1608,1595],{"class":947},[851,1610,1611],{"class":867},".database_password.get_secret_value() ",[851,1613,1543],{"class":863},[851,1615,1616],{"class":856}," \"change-me\"",[851,1618,1587],{"class":867},[851,1620,1621,1624,1627,1629,1632],{"class":691,"line":879},[851,1622,1623],{"class":863},"        raise",[851,1625,1626],{"class":947}," ValueError",[851,1628,1091],{"class":867},[851,1630,1631],{"class":856},"\"APP_DATABASE_PASSWORD was not injected in production\"",[851,1633,1040],{"class":867},[851,1635,1636,1639],{"class":691,"line":893},[851,1637,1638],{"class":863},"    return",[851,1640,1641],{"class":947}," self\n",[590,1643,1644,1645,1274,1647,1650,1651,1655],{},"At startup, log the resolved settings once. Because credentials are ",[604,1646,618],{},[604,1648,1649],{},"logger.info(\"settings=%r\", settings)"," is safe, and it gives you a line in your log aggregator that answers \"what configuration was this pod actually running\" without a shell into the container. If you already emit structured logs, ",[650,1652,1654],{"href":1653},"\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids\u002F","Structured JSON Logging with Request IDs"," covers the format.",[656,1657,1659],{"id":1658},"trade-offs-and-when-not-to","Trade-offs and When Not To",[590,1661,1662,1668,1669,1672],{},[593,1663,1664,1665,1667],{},"A ",[604,1666,606],{}," file is not a secrets manager."," It has no rotation, no audit trail, no per-consumer access control, and it sits on disk in the container image or on a mounted volume. For anything with real blast radius, fetch from Vault, AWS Secrets Manager or your platform's equivalent at startup and pass the results into ",[604,1670,1671],{},"Settings(...)"," as constructor arguments — the highest-priority source, which is precisely why that source exists.",[590,1674,1675,1678,1679,642],{},[593,1676,1677],{},"Secrets fetched at startup do not rotate."," A settings object built once at import time holds whatever was valid at boot. If your credentials rotate on a schedule shorter than your deploy cadence, you need a refreshable client rather than a frozen settings field, and the refresh belongs in the lifespan — see ",[650,1680,1682],{"href":1681},"\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Flifespan-events-vs-startup-shutdown\u002F","Lifespan Events vs Startup and Shutdown",[590,1684,1685,1690,1691,1693,1694,1697,1698,1700,1701,1703],{},[593,1686,1687,1689],{},[604,1688,618],{}," is a guardrail, not a control."," It stops accidents. It does not stop ",[604,1692,826],{}," appearing in a debug print, does not encrypt memory, and does not survive ",[604,1695,1696],{},"model_dump()"," unless you check — dumping a model containing a ",[604,1699,618],{}," yields the ",[604,1702,618],{}," object in Python mode and raises a serializer warning in JSON mode rather than silently emitting the value.",[590,1705,1706,1709],{},[593,1707,1708],{},"Defaults are dangerous in production."," A default is the right call for a local development port. It is the wrong call for a database URL, because a missing variable then produces a working app pointed somewhere unexpected instead of a loud failure. Leave production-critical fields required and let the app refuse to start.",[590,1711,1712,1713,642],{},"For a comparison of pydantic-settings against the alternatives, see ",[650,1714,425],{"href":1715},"\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fpydantic-settings-vs-dynaconf-vs-python-decouple\u002F",[656,1717,1719],{"id":1718},"faq","FAQ",[590,1721,1722,1725,1726,1729,1730,1732,1733,1735],{},[593,1723,1724],{},"What order does pydantic-settings resolve sources in?","\nHighest priority first: arguments passed to ",[604,1727,1728],{},"Settings()",", then process environment variables, then the ",[604,1731,606],{}," file, then the secrets directory, then the field defaults on the class. A real environment variable therefore always beats the same key in a ",[604,1734,606],{}," file.",[590,1737,1738,1741,1742,1745],{},[593,1739,1740],{},"Should I commit .env files to the repository?","\nCommit a ",[604,1743,1744],{},".env.example"," listing every key with placeholder values, and commit non-sensitive per-environment files if it helps. Never commit a file containing real credentials — secrets should arrive as injected environment variables or through a secrets directory mounted by the orchestrator.",[590,1747,1748,1751,1752,623,1754,1756,1757,1759],{},[593,1749,1750],{},"Does SecretStr actually stop a secret from being logged?","\nIt masks the value in ",[604,1753,622],{},[604,1755,626],{},", which covers accidental logging of the settings object, f-strings and tracebacks. It does not encrypt anything and does not stop code that calls ",[604,1758,826],{},", so it is a guardrail against accidents rather than a security control.",[590,1761,1762,1765,1766,1768,1769,1772,1773,1776,1777,1779],{},[593,1763,1764],{},"How do I load a different .env file per environment?","\nChoose the path before constructing ",[604,1767,641],{},", usually from a bootstrap variable such as ",[604,1770,1771],{},"APP_ENV"," read directly from ",[604,1774,1775],{},"os.environ",", and pass it as ",[604,1778,799],{},". Loading the file inside the class means the class has to know which environment it is in before it has been configured.",[590,1781,1782,1785,1786,1788,1789,1792,1793,792,1795,1797,1798,1801],{},[593,1783,1784],{},"Why is my environment variable being ignored?","\nAlmost always a prefix mismatch. With ",[604,1787,787],{}," set to ",[604,1790,1791],{},"APP_"," the field ",[604,1794,791],{},[604,1796,795],{},", not ",[604,1799,1800],{},"DATABASE_URL",". Print the resolved settings at startup — with secrets masked — so a misnamed variable shows up immediately.",[656,1803,1805],{"id":1804},"related-reading","Related Reading",[597,1807,1808,1817,1823,1828,1835],{},[600,1809,1810,1813,1814,1816],{},[593,1811,1812],{},"Up to the topic:"," ",[650,1815,653],{"href":652}," for settings as a typed object.",[600,1818,1819,1820,642],{},"The foundations of the settings class: ",[650,1821,419],{"href":1822},"\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings\u002F",[600,1824,1825,1826,642],{},"Choosing the library: ",[650,1827,425],{"href":1715},[600,1829,1830,1831,642],{},"Where settings are read and clients are built: ",[650,1832,1834],{"href":1833},"\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns\u002F","Application Factory Patterns",[600,1836,1837,1838,642],{},"Keeping the startup log useful: ",[650,1839,1654],{"href":1653},[1841,1842,1843],"style",{},"html pre.shiki code .sYEJz, html code.shiki .sYEJz{--shiki-default:#032563}html pre.shiki code .sTJeM, html code.shiki .sTJeM{--shiki-default:#A0111F}html pre.shiki code .sigWx, html code.shiki .sigWx{--shiki-default:#0E1116}html pre.shiki code .sacAq, html code.shiki .sacAq{--shiki-default:#023B95}html pre.shiki code .sV4o_, html code.shiki .sV4o_{--shiki-default:#702C00}html pre.shiki code .sFeEa, html code.shiki .sFeEa{--shiki-default:#66707B}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s3dhs, html code.shiki .s3dhs{--shiki-default:#622CBC}",{"title":847,"searchDepth":860,"depth":860,"links":1845},[1846,1847,1848,1849,1850,1851,1852],{"id":658,"depth":860,"text":659},{"id":761,"depth":860,"text":762},{"id":830,"depth":860,"text":831},{"id":1446,"depth":860,"text":1447},{"id":1658,"depth":860,"text":1659},{"id":1718,"depth":860,"text":1719},{"id":1804,"depth":860,"text":1805},"2026-07-20","Layer FastAPI settings from class defaults through a per-environment .env file to injected environment variables, using SettingsConfigDict and SecretStr safely.","md",[1857,1859,1861,1863,1865],{"q":1724,"a":1858},"Highest priority first: arguments passed to Settings(), then process environment variables, then the .env file, then the secrets directory, then the field defaults on the class. A real environment variable therefore always beats the same key in a .env file.",{"q":1740,"a":1860},"Commit a .env.example listing every key with placeholder values, and commit non-sensitive per-environment files if it helps. Never commit a file containing real credentials — secrets should arrive as injected environment variables or through a secrets directory mounted by the orchestrator.",{"q":1750,"a":1862},"It masks the value in repr and str, which covers accidental logging of the settings object, f-strings and tracebacks. It does not encrypt anything and does not stop code that calls get_secret_value(), so it is a guardrail against accidents rather than a security control.",{"q":1764,"a":1864},"Choose the path before constructing Settings, usually from a bootstrap variable such as APP_ENV read directly from os.environ, and pass it as env_file. Loading the file inside the class means the class has to know which environment it is in before it has been configured.",{"q":1784,"a":1866},"Almost always a prefix mismatch. With env_prefix set to APP_ the field database_url reads APP_DATABASE_URL, not DATABASE_URL. Print the resolved settings at startup — with secrets masked — so a misnamed variable shows up immediately.",null,{"slug":1869,"breadcrumb":1870},"secrets-and-env-files-per-environment",[1871,1873,1876,1877],{"label":1872,"path":1359},"Home",{"label":1874,"path":1875},"Core Architecture & Routing Patterns","\u002Fcore-architecture-routing-patterns\u002F",{"label":653,"path":652},{"label":1878,"path":1879},"Secrets and Env Files Per Environment","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fsecrets-and-env-files-per-environment\u002F",{"title":431,"description":1854},"article","5RYiC9AClK6hPemwH9hWyHMFwozeQz0OlLC98EjxzFg",[1867,1867],1784588202739]