Server and Environment Configuration
In FastAPI, configuring the target servers for your API is essential for generating accurate OpenAPI documentation. This allows clients to know which base URLs are available for different environments, such as production, staging, or local development.
The core of this configuration lies in the Server and ServerVariable models defined in fastapi/openapi/models.py, which are used to populate the servers field in the generated OpenAPI schema.
Defining Environment Servers
When instantiating a FastAPI application, you can provide a list of dictionaries to the servers parameter. Each dictionary corresponds to the Server model.
The Server Model
The Server model (found in fastapi/openapi/models.py) defines the structure for each server entry:
class Server(BaseModelWithConfig):
url: AnyUrl | str
description: str | None = None
variables: dict[str, ServerVariable] | None = None
url: The base URL for the server. It can be an absolute URL or a relative path (like/).description: An optional string describing the environment.variables: An optional dictionary for dynamic path resolution.
Basic Configuration Example
A common use case is defining separate URLs for staging and production environments. This is demonstrated in docs_src/behind_a_proxy/tutorial003_py310.py:
from fastapi import FastAPI
app = FastAPI(
servers=[
{"url": "https://stag.example.com", "description": "Staging environment"},
{"url": "https://prod.example.com", "description": "Production environment"},
],
)
When you visit the /docs page, Swagger UI will provide a dropdown menu allowing users to select which server to send requests to.
Dynamic Path Resolution with Server Variables
For more complex scenarios, you can use ServerVariable to define dynamic parts of your server URLs. This is useful when you have multiple subdomains or want to allow users to toggle between protocols (HTTP/HTTPS).
The ServerVariable Model
The ServerVariable model (also in fastapi/openapi/models.py) allows you to define constraints and defaults for URL placeholders:
class ServerVariable(BaseModelWithConfig):
enum: Annotated[list[str] | None, Field(min_length=1)] = None
default: str
description: str | None = None
enum: An optional list of allowed values for the variable.default: The default value to use if none is provided.description: An optional description of the variable.
Using Variables in URLs
Variables are denoted by curly braces {} in the server URL. The keys in the variables dictionary must match the names inside the braces.
app = FastAPI(
servers=[
{
"url": "https://{username}.example.com",
"description": "User-specific sandbox",
"variables": {
"username": {
"default": "demo",
"description": "The username for the sandbox environment"
}
}
}
]
)
Automatic Server Generation and root_path
FastAPI has built-in logic to handle applications running behind proxies or mounted at sub-paths. This involves the root_path and the root_path_in_servers configuration.
Interaction with root_path
If your application is running behind a proxy that strips a path prefix (e.g., Traefik or Nginx), you typically set a root_path. By default, FastAPI automatically prepends this root_path to the servers list in the OpenAPI schema so that the interactive documentation works correctly.
This logic is implemented in the setup method of the FastAPI class in fastapi/applications.py:
# Inside FastAPI.setup() in fastapi/applications.py
async def openapi(req: Request) -> JSONResponse:
root_path = req.scope.get("root_path", "").rstrip("/")
schema = self.openapi()
if root_path and self.root_path_in_servers:
server_urls = {s.get("url") for s in schema.get("servers", [])}
if root_path not in server_urls:
schema = dict(schema)
schema["servers"] = [{"url": root_path}] + schema.get(
"servers", []
)
return JSONResponse(schema)
Disabling Automatic Servers
If you prefer to have full control over the servers list and do not want FastAPI to automatically include the root_path, you can set root_path_in_servers=False in the FastAPI constructor.
This is useful when you have already explicitly defined all necessary environment URLs in the servers list and want to avoid redundancy.
app = FastAPI(
root_path="/api/v1",
root_path_in_servers=False,
servers=[
{"url": "https://prod.example.com/api/v1", "description": "Production"}
]
)