Deploy a FastAPI app on Vercel
Deploy a FastAPI app to Vercel with the Python runtime and Vercel Functions.
Vercel looks for a FastAPI instance named app at supported entrypoints in
your repository.
Create a FastAPI app or use an existing one:
Initialize a new FastAPI project with the Vercel CLI init command:
vc init fastapiThis clones the FastAPI example repository in a directory called fastapi.
To run a FastAPI application on Vercel, define an app instance that initializes FastAPI at a supported entrypoint:
app.py,index.py,server.py,main.py,wsgi.py, orasgi.py- the same filenames inside
src/orapp/
For example:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Python": "on Vercel"}To point Vercel to a FastAPI app in a custom module, set tool.vercel.entrypoint in pyproject.toml:
[tool.vercel]
entrypoint = "backend.server:app"The tool.vercel.entrypoint value tells Vercel to look for a FastAPI instance named app in ./backend/server.py.
The build property in [tool.vercel.scripts] defines the Build Command for FastAPI deployments. It runs after dependencies are installed and before your application is deployed.
[tool.vercel.scripts]
build = "python build.py"For example:
def main():
print("Running build command...")
with open("build.txt", "w") as f:
f.write("BUILD_COMMAND")
if __name__ == "__main__":
main()Use vercel dev to run your application locally.
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
vercel devDeploy the project by connecting your Git repository or by using the Vercel CLI:
vc deployVercel supports two methods for serving frontend and static assets with FastAPI.
Place files in a public/ directory at your project root. Vercel serves them
from the CDN at the matching root URL paths. For example,
public/logo.svg is served at /logo.svg. Default response
headers apply unless you override them in vercel.json.
from fastapi import FastAPI
from fastapi.responses import RedirectResponse
app = FastAPI()
@app.get("/favicon.ico", include_in_schema=False)
async def favicon():
# /vercel.svg is served automatically from public/vercel.svg.
return RedirectResponse("/vercel.svg", status_code=307)When using app.frontend() or
app.mount() with StaticFiles,
files are promoted to the CDN at build time:
from fastapi import FastAPI
app = FastAPI()
@app.get("/api/hello")
def hello():
return {"message": "Hello"}
app.frontend("/", directory="dist")from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
app.mount("/assets", StaticFiles(directory="assets"), name="assets")Promoted source directories are kept in the function bundle by default so the app can read from them at runtime. To exclude them and serve files from the CDN only, set exclude = true:
[tool.vercel.fastapi.static]
exclude = trueSee Configuration for all available settings.
Files are served from the CDN at the mount's URL prefix. Route declaration order determines which wins when a route and a CDN file share the same path:
- A route declared before the mount takes priority over CDN files. Matching requests reach the function.
- A route declared after the mount does not take priority. Matching requests are served from the CDN.
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
# Declared before the mount, so this route wins over any CDN file at this path.
@app.get("/static/protected.json")
def protected():
return {"access": "denied"}
app.mount("/static", StaticFiles(directory="static"))The bare mount root (for example, /static) always reaches the function.
StaticFiles redirects it to the trailing-slash form.
app.frontend() registers a low-priority frontend build. Every API route takes
priority over frontend files regardless of declaration order.
The fallback parameter controls CDN behavior when no file matches a request
under the mount:
fallback value | File served | Status | When applied |
|---|---|---|---|
"auto" | 404.html if present, else index.html | 404 or 200 | See notes below |
"index.html" | index.html | 200 | Navigation requests only |
"404.html" | 404.html | 404 | All misses |
None | n/a | n/a | Unmatched paths reach the function |
An index.html fallback applies to navigation requests only: requests with an
explicit text/html or application/xhtml+xml Accept header and an
extension-less final URL segment (for example, /dashboard but not
/dashboard/app.js). All other misses reach the function. A 404.html fallback
applies to every miss regardless of the Accept header. If "auto" is set but
neither file exists in the build directory, no fallback is applied.
Fallback routes apply to GET and HEAD requests only. All other methods
always reach the function.
CDN-served files bypass the function entirely, so middleware handlers and Depends() guards do not run for them.
Vercel detects these cases and keeps the affected static files and frontends in the function rather than promoting them to the CDN:
- Top-level middleware: All static mounts and frontends stay in the function.
- Sub-app middleware: Only that sub-app's mounts stay in the function. Mounts elsewhere are still promoted.
- Frontend dependencies: Frontends with
Depends()guards stay in the function.
Set cdn = true to promote files to the CDN even when middleware or dependency guards are present:
[tool.vercel.fastapi.static]
cdn = trueAll settings go under [tool.vercel.fastapi.static] in pyproject.toml.
| Setting | Value | Description |
|---|---|---|
cdn | omitted (default) | CDN promotion enabled. Disabled automatically when middleware or dependency guards are present. |
cdn | true | CDN promotion always enabled, even when middleware or dependency guards are present. |
cdn | false | CDN promotion disabled. All requests reach the function. |
exclude | false (default) | Promoted source directories are kept in the function bundle. |
exclude | true | Promoted source directories are excluded from the function bundle. |
You can use FastAPI lifespan events to manage startup and shutdown logic, such as initializing and closing database connections.
from contextlib import asynccontextmanager
from fastapi import FastAPI
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup logic
print("Starting up...")
await startup_tasks()
yield
# Shutdown logic
await cleanup_tasks()
app = FastAPI(lifespan=lifespan)When you deploy a FastAPI app to Vercel, it becomes a single Vercel Function. Vercel uses Fluid compute by default, so the function scales with traffic.
To configure that function, add an entry to the functions
object in vercel.json keyed by your
resolved entrypoint file. For example, to let an app defined in app/main.py
run for up to 60 seconds, set maxDuration:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"functions": {
"app/main.py": {
"maxDuration": 60
}
}
}For more options, see Configuring
functions and the functions
property.
All Vercel Functions limitations apply to FastAPI applications, including:
- Application size: The FastAPI application becomes a single bundle, which has a standard bundle size limit of 500MB. Large Functions support Python bundles up to 5GB on Fluid compute when enabled (public beta).
For more about deploying FastAPI on Vercel, see:
Was this helpful?