How does Vercel deploy FastAPI is a question with a surprisingly narrow answer: Vercel turns your entire FastAPI app into a single serverless function, runs it on AWS Lambda under the hood, and enforces a 500MB bundle size limit and a default 10-second execution timeout on the result. The DX is excellent. The path is fast. The limits are real, and the three situations where Vercel’s model breaks for FastAPI are the three situations where most production FastAPI apps eventually land.
This post explains the actual deployment mechanism (not the marketing version), walks through a real working vercel.json + pyproject.toml setup, and names the three patterns where you should reach for a different platform — RunxBuild, Fly.io, Railway, Render, or a self-managed container — instead of forcing FastAPI into a serverless shape it wasn’t designed for.
Table of contents
- The one-paragraph answer
- The actual deployment mechanism
- A working setup, end to end
- What the limits actually are
- When the model works
- When the model breaks
- How to migrate off Vercel when you need to
- A working deployment, end to end
- A short comparison of “deploy FastAPI” options
- The answer in 30 seconds
- FAQ
The one-paragraph answer
Vercel reads your repo, finds a file that exports a FastAPI() instance named app at a supported entrypoint (app.py, index.py, main.py, server.py, asgi.py, or any of those inside src/, app/, or api/), wraps that instance in a serverless function handler, bundles the function with your Python dependencies into a single deployment artifact, and runs that artifact on AWS Lambda via Vercel’s own infrastructure. The function is exposed at the URL Vercel assigns your project (or your custom domain), and incoming HTTP requests are routed to the function. Cold starts apply. Per-invocation billing applies. The 500MB size limit applies. The execution time limit applies.
That is the answer. The rest of this post is the part the docs cover in one paragraph and the Reddit threads cover in 200 messages: what the model means in practice, how to make it work for a typical app, and the three cases where you should not use it.
The actual deployment mechanism
Here is what Vercel does, step by step, when you point it at a FastAPI repo. The official docs (at vercel.com/docs/frameworks/backend/fastapi) cover the same steps, but they are written for someone who already understands serverless. The translation is below.
Step 1: Vercel detects the framework. When you connect a GitHub repo or run vc init fastapi, Vercel’s build system looks for the FastAPI markers in your codebase. The strongest marker is an app instance of class FastAPI at a known entrypoint. Vercel also looks at pyproject.toml for the [tool.vercel] section, which is where you can override the default entrypoint with tool.vercel.entrypoint = "backend.server:app".
Step 2: Vercel builds the Python bundle. Vercel installs your project’s Python dependencies (from requirements.txt or the dependencies array in pyproject.toml), compiles your code if you have a build step (you can configure this with tool.vercel.scripts.build = "python build.py"), and packages the result into a deployment bundle. The bundling process removes __pycache__ and .pyc files to reduce size, but Vercel does not do application-level bundling; whatever your build step produces is what gets deployed.
Step 3: Vercel wraps the FastAPI app in a function handler. This is the part that surprises people. Vercel does not run FastAPI as a long-running process. It takes your FastAPI instance and adapts it to the AWS Lambda / Vercel Functions request model: a single function that handles one HTTP request, runs to completion (or until the timeout), and returns a response. The wrapping is transparent; you write standard FastAPI code with standard ASGI middleware and routes, and the platform makes it work in a serverless context.
Step 4: Vercel deploys the function to its infrastructure. The deployment artifact is uploaded to Vercel’s CDN and replicated to the edge. The next HTTP request to your URL hits the nearest edge node, which routes to the function, which runs your FastAPI code, which returns a response. Cold starts (the time to spin up a fresh Python process for the first request after a quiet period) are real and visible; Vercel uses Fluid compute to scale the function horizontally with traffic, but the first request after a cold start pays the latency.
The whole process from git push to live URL is typically under two minutes for a small FastAPI app. The DX is genuinely good. The model is a real fit for a large class of FastAPI apps.
The model is not a fit for the rest.
A working setup, end to end
Here is the minimum viable FastAPI app that deploys to Vercel without any configuration beyond the pyproject.toml. This is a real setup I have used; the file names and the entrypoint are exactly what Vercel expects.
.
├── api/
│ └── index.py
├── pyproject.toml
└── README.md
api/index.py:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"status": "ok"}
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}
pyproject.toml:
[project]
name = "my-fastapi-app"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"fastapi>=0.110",
"uvicorn>=0.27",
]
[tool.vercel]
entrypoint = "api.index:app"
That is the whole thing. git push to your main branch, Vercel detects the FastAPI app at api/index.py, installs the dependencies, wraps the app in a function, deploys, and the URL is live in about 90 seconds. The same setup with a requirements.txt instead of pyproject.toml works identically; Vercel supports both.
A few details that matter in practice:
- The
appinstance must be namedapp. Vercel looks for anappsymbol in the entrypoint module; anything else (e.g.,application = FastAPI()) is ignored. - The entrypoint supports custom paths via
tool.vercel.entrypoint. The default works for a single-file app; the override is needed when the app is in a custom module path likebackend.server:app. vercel.jsoncan override any of this. If you have avercel.jsonwith a build command, it takes precedence overpyproject.toml.- Local dev works the same as production:
vercel devruns the function locally with the same entrypoint resolution.
That last one is the DX win. You don’t have a different runtime between local and production. The same pyproject.toml and the same api/index.py produce the same behavior in both.
What the limits actually are
The Vercel Functions model imposes limits on what FastAPI can do. Most apps do not hit them. The apps that do hit them are the apps that should not be on Vercel. Knowing which is which saves a weekend of debugging.
500MB deployment bundle size. This is the most-cited Vercel limit and the one FastAPI apps are most likely to hit. The bundle includes your code, your dependencies, and the Python runtime that Vercel bundles in. FastAPI itself is small. pydantic is small. uvicorn is small. sqlalchemy is small. pandas is not. numpy is not. torch is not. transformers is definitely not. A FastAPI app that imports a heavy ML library will exceed 500MB before it exceeds 100 lines of code.
The first thing to do if your deploy is failing with a “Function size exceeds” error is to look at which dependencies are eating the budget. pandas and numpy together are ~200MB; that’s 40% of the limit gone before your code starts. Heavy ML frameworks like torch and transformers will exceed the limit on their own. The fix is to either (a) move the heavy dependency to a separate service, (b) use a lighter alternative, or (c) move to a platform that doesn’t have a 500MB limit.
Default 10-second execution timeout. Configurable up to a higher maximum (60s on hobby, 300s on pro, 900s on enterprise, last I checked). The limit is per-request, not per-function. A FastAPI request that runs a long query, calls a slow external API, or does any significant computation is at risk of hitting it.
The first thing to check if your requests are timing out is whether you have any blocking I/O that you could offload. Long database queries can be moved to a background worker. Slow external API calls can be moved to a job queue. File processing can be moved to a background task. The 10-second default is generous for an API endpoint; it is not generous for a batch operation.
No persistent WebSocket connections. Vercel Functions are request-response. A FastAPI app that uses WebSockets will not work on Vercel Functions. The docs say “FastAPI app becomes a single Vercel Function” and a single Vercel Function is a request-response function. WebSockets require a long-running connection, which is the opposite of request-response.
No long-running background processes. Same reason. A FastAPI app that spins up a background task on startup (a queue worker, a scheduled job, an event listener) will lose that background task when the function instance is recycled. The platform manages function lifecycle, and the lifecycle is “start on request, stop on idle.”
Cold starts on the first request after idle. Vercel publishes a default of 250MB unzipped deployment bundle size and an aggressive instance recycling policy. A function that has not received a request in a few minutes will be cold-started on the next request, which adds latency (typically 500ms to 2s for a small Python app). For a high-traffic app this is invisible. For a low-traffic app this is the difference between “snappy” and “feels slow.”
Functions are stateless. Vercel Functions do not have a filesystem that persists between invocations. The /tmp directory is the only writable storage, and it is scoped to the function instance. A FastAPI app that writes to a local file and expects the file to be there on the next invocation will be surprised.
When the model works
The Vercel + FastAPI combination is genuinely good for a class of app that is large in number: the stateless request-response API.
An API gateway. A webhook receiver. A content API. A JSON backend for a React or Next.js front end. An API that talks to a managed Postgres, a managed Redis, a managed S3, and a third-party API like Stripe or Twilio. A simple CRUD app with auth, sessions, and rate limiting. A single-page app’s backend. An internal tool that gets called by a few hundred people a day.
The Vercel + FastAPI combination is also good for the app most indie hackers and small teams are actually building: a small API with a few endpoints, a single managed Postgres, a couple of third-party integrations, and a front end that gets more traffic than the API. The free tier is generous enough that the prototype is free; the paid tier is reasonable enough that a real product is affordable.
The Vercel + FastAPI combination is the right answer for a fastapi app that is part of a larger Vercel-deployed front end. If your Next.js site is on Vercel and your API is FastAPI, the same dashboard deploys both, the same CI builds both, the same domain routes both. The integration story is better than deploying the API elsewhere.
When the model breaks
Three patterns hit the limits in production. Knowing them in advance is the difference between “the Vercel deploy failed” and “the Vercel deploy was always going to fail.”
Pattern 1: Long-running connections. WebSockets, Server-Sent Events with long-lived streams, file uploads that take more than the timeout, anything that holds a connection open. Vercel Functions is request-response; the connection is closed when the response is returned. A FastAPI app that uses WebSocket from FastAPI or sse-starlette for streaming will not work on Vercel Functions.
The fix is to use a different runtime for the WebSocket part of the app (a container platform, a dedicated WebSocket service, or a different serverless tier that supports WebSockets) and keep the Vercel + FastAPI combination for the request-response API. Or use a third-party service for the WebSocket part (Pusher, Ably, Soketi) and keep the rest on Vercel.
Pattern 2: Heavy dependency footprint. ML inference, image processing with Pillow, PDF generation with WeasyPrint, anything that pulls in numpy/pandas/torch/transformers. The 500MB bundle limit will get hit long before the application is feature-complete.
The fix is to move the heavy dependency out of the FastAPI app. A separate service for inference, an external API for image processing, a serverless function specifically for the heavy work, or a different platform. The Vercel + FastAPI combination is wrong for “FastAPI is the thin wrapper around a giant ML pipeline.”
Pattern 3: Background processing. A queue worker that processes jobs in the background, a scheduled task that runs every minute, an event listener that consumes from a stream. Vercel Functions does not run processes; it runs functions in response to requests. A FastAPI app that uses BackgroundTasks for quick fire-and-forget work is fine; a FastAPI app that expects a long-running worker to be alive between requests is not.
The fix is the same as the WebSocket fix: use a different runtime for the background work (a worker on a container platform, a dedicated queue service like SQS or Cloud Tasks, a cron service like EasyCron) and keep the Vercel + FastAPI combination for the request-response part of the app.
How to migrate off Vercel when you need to
The good news is that the FastAPI app you wrote for Vercel is the same FastAPI app you’ll deploy elsewhere. The Vercel-specific bits are the entrypoint and the deploy config; the application code is portable.
The migration is:
- Add a
Dockerfilethat installs your dependencies and starts the app withuvicorn. The Dockerfile is the new entrypoint; the rest of the app is unchanged. - Deploy the Dockerfile to a platform that supports long-running containers. RunxBuild, Fly.io, Railway, Render, DigitalOcean App Platform, AWS ECS, Google Cloud Run — the choice is less important than the fact that you have a choice.
- Move the long-running work (WebSockets, background workers, heavy dependencies) to the container platform, which can run them. Keep the Vercel + FastAPI combo for the parts that fit it.
A typical split: Vercel for the front end and the small JSON API, RunxBuild or Fly.io for the WebSocket layer and the worker process. The same Postgres, the same Redis, the same DNS. The split is about which platform runs which code, not about which platform owns which data.
The most common reason teams get stuck on Vercel is that they try to fit the whole app into one platform. The most common reason teams succeed on Vercel is that they treat it as a great option for a specific class of work, not as the only option for everything.
A working deployment, end to end
Here is the FastAPI app, the config, and the deploy command. This is a real setup; the file names and the entrypoint are exactly what Vercel expects.
api/index.py:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
def read_root():
return {"status": "ok"}
@app.get("/health")
def health():
return {"status": "healthy"}
pyproject.toml:
[project]
name = "my-fastapi-app"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"fastapi>=0.110",
"uvicorn>=0.27",
]
[tool.vercel]
entrypoint = "api.index:app"
vercel.json (optional, if you want to override defaults):
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"buildCommand": "pip install -r requirements.txt",
"framework": null
}
The deploy commands:
# Install Vercel CLI
npm i -g vercel
# From inside the project, deploy to preview
vercel
# Deploy to production
vercel --prod
The output of vercel --prod is the production URL. The output of vercel is a preview URL that gets a unique URL per commit. The same FastAPI code runs in both.
This is a real setup. The only thing I have not done is added a database. The next step in a real app is to add a managed Postgres (the kind RunxBuild, Neon, or Supabase provides) and a DATABASE_URL environment variable in the Vercel project settings. The FastAPI code reads DATABASE_URL from the environment and connects to the database on every request; the connection pool is what keeps the database from being overwhelmed.
A short comparison of “deploy FastAPI” options
The “how does Vercel deploy FastAPI” question is part of a larger “where should I deploy FastAPI” question. A short comparison, with the same FastAPI code as the input.
| Platform | How FastAPI runs | Cold start | Bundle limit | WebSockets | Background work | Best for |
|---|---|---|---|---|---|---|
| Vercel | Serverless function (Lambda) | ~500ms–2s | 500MB | No | No | Request-response APIs, JSON backends |
| RunxBuild | Container or function | ~50ms–200ms | None práctico | Yes | Yes | Full-stack apps with backend + DB + agent |
| Fly.io | Container (Firecracker VM) | ~50ms–500ms | None | Yes | Yes | Stateful APIs, WebSockets, regional deploys |
| Railway | Container | ~100ms–1s | None práctico | Yes | Yes | Quick deploys, simple stacks |
| Render | Container or web service | ~100ms–1s | None práctico | Yes | Yes | Production web services, simple deploys |
| AWS ECS / Fargate | Container (EC2/Fargate) | None (always on) | None | Yes | Yes | Enterprise production workloads |
The right answer depends on what the app does. The Vercel combination is the right answer for the top of the list. The container combinations are the right answer for the rest. A team that has both kinds of work — a request-response API and a long-running worker — splits the app between two platforms, not because one platform is bad, but because no single platform is the right answer for every kind of work.
The answer in 30 seconds
Vercel deploys FastAPI by turning it into a single serverless function. The deployment is fast, the DX is good, the free tier is generous, and the integration with Vercel’s front-end and edge products is excellent. The model has a 500MB bundle size limit, a default 10-second execution timeout, no WebSocket support, and no long-running background processes. The model is a great fit for a stateless request-response API and a poor fit for an app with WebSockets, heavy ML dependencies, or background processing. When the model doesn’t fit, the migration path is straightforward: add a Dockerfile, deploy the app to a container platform, and let each platform do what it does best.
That is the whole story. The rest is in the docs and the Reddit threads, and the docs are shorter.
Frequently asked questions
Can I deploy FastAPI to Vercel?
Yes. Vercel supports FastAPI as a first-class framework. The setup requires a FastAPI() instance named app at a supported entrypoint (app.py, index.py, main.py, server.py, asgi.py, or any of those inside src/, app/, or api/) and either a pyproject.toml or a requirements.txt declaring the dependencies. The deploy is a git push to the connected repo or a vercel --prod from the CLI. The URL is live in about 90 seconds for a small app.
Does Vercel support FastAPI’s WebSocket support?
No. Vercel Functions is a request-response runtime, and WebSockets require a long-running connection that survives multiple request-response cycles. A FastAPI app that uses WebSocket will not work on Vercel. The recommended pattern is to keep the WebSocket part of the app on a container platform (RunxBuild, Fly.io, Railway, Render) or a third-party WebSocket service (Pusher, Ably, Soketi) and run the rest of the FastAPI app on Vercel.
What is the bundle size limit for FastAPI on Vercel?
500MB. The limit is the unzipped size of the deployment bundle, which includes your code, your Python dependencies, and the Python runtime that Vercel bundles in. A typical FastAPI app with a few hundred KB of dependencies is well under the limit. A FastAPI app that imports heavy libraries like numpy, pandas, torch, or transformers is at risk of exceeding it. The fix is to move the heavy dependency out of the FastAPI app or to a platform that does not have the 500MB limit.
How does Vercel handle Python cold starts?
Vercel publishes a default of 250MB unzipped deployment bundle and an aggressive instance recycling policy. A function that has not received a request in a few minutes will be cold-started on the next request, which adds latency (typically 500ms to 2s for a small Python app). Vercel uses Fluid compute to scale horizontally with traffic, so the cold start only affects the first request after a quiet period. A high-traffic app does not experience cold starts. A low-traffic app can mitigate cold starts with a keep-alive ping or by using Vercel’s warmer feature if available on the plan.
Can I use a database with FastAPI on Vercel?
Yes. Vercel Functions can connect to any database with a public connection string — Postgres, MySQL, MongoDB, Redis, or a managed equivalent like RunxBuild Postgres, Neon, Supabase, PlanetScale, or Upstash. The recommended pattern is to use a managed database (so the database is not a function that Vercel has to run) and to put the connection string in a Vercel environment variable. The FastAPI code reads the variable on startup, creates a connection pool, and reuses the pool across requests. The 500MB bundle limit does not apply to the database.
Is Vercel cheaper than running FastAPI on a container platform?
It depends on the workload. Vercel is almost always cheaper for a low-traffic app because you pay per invocation and there are no idle costs. A container platform is almost always cheaper for a high-traffic app because you pay a fixed monthly fee and the per-invocation cost of Vercel scales linearly. The break-even depends on traffic and the specific plan, but it is usually around tens of thousands of requests per day. The honest answer is “use Vercel until you don’t, and the migration is easy when you don’t.”
Can I deploy FastAPI to Vercel with a Dockerfile?
Vercel does support Docker-based deployments, but the FastAPI experience is designed around the Python runtime’s automatic detection, not around a custom Dockerfile. If you want the Dockerfile experience, RunxBuild, Fly.io, Railway, and Render are better fits. The Vercel + FastAPI combination is meant for the “git push and it just works” developer experience, not the “I want to control every layer of the build” developer experience. Both are valid; pick the one that matches your team’s preference.
How this fits the rest of the stack
A FastAPI app on a serverless platform is a great way to start, and the production move is where the cost model becomes real. Serverless platforms charge per request, per GB-second, and per bandwidth, and the team’s mental model for the project cost is the sum of those numbers. The RunxBuild hosting calculator is the right place to model that — pick the request rate, the runtime, the memory, the bandwidth, and the database, and the calculator shows what the FastAPI deploy costs at the team’s actual usage rather than what the free tier hides.
Useful related references: