# How to ship a Flask app on Vercel

**Author:** Ben Sabic

---

[Flask](https://flask.palletsprojects.com/) is a lightweight Web Server Gateway Interface (WSGI) web framework for Python. It gives you a small core, a built-in development server and debugger, request routing, and Jinja templating, and it leaves choices like your database and authentication to you through a large ecosystem of extensions.

On Vercel, you can deploy a Flask app with zero configuration: your app becomes a [Vercel Function](https://vercel.com/docs/functions) running on [Fluid compute](https://vercel.com/fluid), and you get response streaming, preview deployments, and observability without extra setup.

This guide walks you through deploying a Flask app to Vercel from a template, the [Vercel CLI](https://vercel.com/docs/cli), or a Git repository, then configuring features such as streaming, request hooks alongside Routing Middleware, cron jobs, the Python version, and observability.

## Prerequisites

Before you begin, make sure you have:

- A [Vercel account](https://vercel.com/signup)
  
- Python 3.12 or newer and a package manager (e.g., pip)
  
- An existing Flask project, or a new one created from a [Flask template](https://vercel.com/templates/flask)
  
- A Git repository on GitHub, GitLab, or Bitbucket (if you want Git-based deployments)
  
- Vercel CLI installed (`npm i -g vercel`)
  

## How it works

When you deploy a Flask app, Vercel detects the framework from your dependencies and builds it for the Python runtime. Your Flask `app` handles every request through a single Vercel Function, which runs on Fluid compute by default. Your app scales with traffic, and you pay only for the compute your function uses, not for idle time.

Because Vercel ships zero-configuration detection for Flask, you don't set a build command or output directory. Vercel reads your project, finds the file that exports your WSGI `app` instance, and applies the correct build settings.

## Deploy your Flask app

You can ship a Flask app to Vercel in three ways. Choose the one that fits where your code lives today.

### Option 1: Deploy from a template

The fastest way to ship a Flask app is to start from a template. Browse the [Flask templates gallery](https://vercel.com/templates/flask), pick a starter, and deploy it. Vercel clones the template to your Git provider, creates a project, and deploys it with zero configuration.

Templates to start from include:

- [**Flask Hello World**](https://vercel.com/templates/python/flask-hello-world): A minimal Flask 3 app that deploys with zero configuration. Start here if you're new to Flask on Vercel.
  
- [**AI SDK with Flask**](https://vercel.com/templates/python/ai-sdk-with-flask): A Flask backend wired up with [AI SDK](https://ai-sdk.dev/) for building AI features and streaming responses.
  
- [**Flask Alt Text Generator**](https://vercel.com/templates/python/flask-alt-text-generator): A Flask API that generates a text description for any image.
  
- [**Next.js Flask Starter**](https://vercel.com/templates/next.js/nextjs-flask-starter): A Flask API paired with a [Next.js](https://nextjs.org/) frontend in a single project.
  

### Option 2: Start a new project with the Vercel CLI

To scaffold a new Flask project locally, use the [Vercel CLI init command](https://vercel.com/docs/cli/init). It clones Vercel's Flask example into a folder named `flask`.

1. Create the project:
   
   `vercel init flask`
   
2. Move into the folder, create a virtual environment, and install dependencies:
   
   `cd flask python -m venv .venv source .venv/bin/activate pip install -r requirements.txt`
   
3. Develop locally at `http://localhost:3000`. Use the Vercel CLI, so your app runs with the same WSGI entry point it uses in production:
   
   `vercel dev`
   
4. Create a [preview deployment](https://vercel.com/docs/deployments/environments). The first run creates a Vercel project link:
   
   `vercel`
   
5. Promote your deployment to production:
   
   `vercel --prod`
   

### Option 3: Deploy an existing Flask app

If you already have a Flask app, deploy it from Git or from the command line.

From Git: Push your project to GitHub, GitLab, or Bitbucket, then import it at [vercel.com/new](https://vercel.com/new). Vercel detects Flask automatically and deploys it with zero configuration.

From the CLI: From your project's root directory, run `vercel` to create a preview deployment, then `vercel --prod` to go live. To pull project settings and environment variables for local development, run:

`vercel link vercel env pull`

For Vercel to detect your app, expose a WSGI `app` instance as a top-level variable named `app` in one of the recognized entry files, such as `app.py` or `index.py`, at your project root or under `src/`, `app/`, or `api/`:

`from flask import Flask app = Flask(__name__) @app.route("/") def index(): return {"message": "Hello from Flask on Vercel"}`

To point Vercel at a Flask app in a custom module, set `tool.vercel.entrypoint` in `pyproject.toml`. For example, `entrypoint = "backend.server:app"` tells Vercel to look for an `app` instance in `./backend/server.py`.

## Use Vercel features with Flask

After your app is deployed, you can layer Vercel features onto it. Some work automatically, and others take a few lines of configuration in `vercel.json`.

### Your app runs as a Vercel Function

Your entire Flask app is served by a single [Vercel Function](https://vercel.com/docs/functions). This function uses Fluid compute by default, which runs multiple requests concurrently within a single instance to reduce cold starts and the cost of I/O-bound work such as API calls and database queries. You don't configure anything to get this behavior.

Because Flask exposes a single WSGI app, Vercel sends every incoming request to that app and lets Flask's router match the path. Your route handlers, request hooks, and error handlers all run inside the function.

### Stream responses

Vercel Functions support streaming on the Python runtime, so you can send data to the client as you produce it instead of waiting for the full response. Return a Flask `Response` backed by a generator to stream text, server-sent events, or AI model output:

`import time from flask import Flask, Response, stream_with_context app = Flask(__name__) @app.route("/stream") def stream(): @stream_with_context def generate(): for chunk in ["Hello", " ", "from", " ", "Flask"]: yield chunk time.sleep(0.2) return Response(generate(), mimetype="text/plain")` Streaming pairs well with Fluid compute, which keeps serving other requests on the same instance while your function produces output. ### Combine Flask hooks with Vercel Routing Middleware Flask and Vercel each have a layer that runs around requests, and they solve different problems. Flask's `before_request` and `after_request` hooks run inside your app, after the request reaches your function. Use them for app-level concerns such as logging, CORS, and authentication: `from flask import Flask, request, g app = Flask(__name__) @app.before_request def authenticate(): g.user = request.headers.get("authorization") @app.after_request def add_headers(response): response.headers["X-Content-Type-Options"] = "nosniff" return response` [Vercel Routing Middleware](https://vercel.com/docs/routing-middleware) runs at the edge, before the request reaches your Flask app. You define it in a `middleware.ts` file at your project root, and you can use it with any framework. Use it for rewrites, redirects, and header changes that should happen before any function runs. The two layers work together, with Routing Middleware shaping the request at the edge and Flask hooks handling it inside your app.

### Serve static assets from the CDN

To serve static files such as images, fonts, or a favicon, place them in the `public/**` directory. Vercel serves them through its [CDN](https://vercel.com/docs/cdn) using default [headers](https://vercel.com/docs/headers), which you can override in `vercel.json`.

> **Note:** Flask's `app.static_folder` is ignored for static files on Vercel. Rely on the `public` directory instead.

### Run scheduled tasks with cron jobs

Vercel [Cron Jobs](https://vercel.com/docs/cron-jobs) trigger a route on a schedule by sending an HTTP GET request to it. Define a route in your Flask app for the task, then register the schedule in `vercel.json`.

**Define the route:**

`import os from flask import Flask, request, jsonify app = Flask(__name__) @app.route("/api/cron/cleanup") def cleanup(): if request.headers.get("authorization") != f"Bearer {os.environ.get('CRON_SECRET')}": return "Unauthorized", 401 # Run your scheduled work here return jsonify(ok=True)`

**Register the schedule:**

`{ "$schema": "https://openapi.vercel.sh/vercel.json", "crons": [{ "path": "/api/cron/cleanup", "schedule": "0 0 * * *" }] }` Vercel runs cron jobs only on production deployments. To stop anyone else from calling the route, set a `CRON_SECRET` environment variable in your project settings. Vercel sends it as a `Bearer` token in the `Authorization` header on every cron invocation, and your handler compares it before running the task. ### Choose your Python version Flask runs on the Python runtime, which uses Python 3.12 by default and also supports 3.13 and 3.14. Set the version with a `.python-version` file, a `requires-python` value in `pyproject.toml`, or a `Pipfile.lock`: `3.13` Vercel applies the same version in `vercel dev` and production. If the requested version isn't defined or supported, Vercel uses the default. For the full set of options, see [Set the Python version for your project](https://vercel.com/docs/functions/runtimes/python/python-version).

### Monitor performance with Observability

[Vercel Observability](https://vercel.com/products/observability) tracks your deployed function automatically, with no setup. Open the Observability page in your project to see invocation counts, error rates, and duration for your Flask app, along with the requests your function makes to external APIs. On [Observability Plus](https://vercel.com/docs/observability/observability-plus), you also get longer retention and a latency breakdown by path.

## Best practices

### Expose your app from a recognized entry point

Vercel finds your Flask app by looking for a top-level `app` instance at a fixed set of locations: `app.py`, `index.py`, `server.py`, `main.py`, `wsgi.py`, or `asgi.py` at your project root or under `src/`, `app/`, or `api/`. Put your app at one of these paths so Vercel detects and deploys it correctly:

`from flask import Flask app = Flask(__name__) # Add your routes here`

### Keep your function bundle small

Python has no automatic tree-shaking, so Vercel bundles every file your project can reach at build time. List only the packages you need at runtime in `requirements.txt` or `pyproject.toml`, and exclude tests, fixtures, and other development files with `excludeFiles` in `vercel.json` to stay under the 500 MB function bundle limit:

`{ "$schema": "https://openapi.vercel.sh/vercel.json", "functions": { "app.py": { "excludeFiles": "{tests/**,**/*.test.py,**/test_*.py,fixtures/**}" } } }`

Match the glob key to your entry file, such as `src/index.py`.

### Develop with the Vercel CLI

Run `vercel dev` for local development instead of Flask's built-in server. It serves your app the same way production does, using your WSGI `app`, so the behavior you test locally matches what you deploy. This also lets you exercise features such as cron routes and your configured Python version before shipping.

## Resources and next steps

- Read the full [Deploy a Flask app on Vercel documentation](https://vercel.com/docs/frameworks/backend/flask)
  
- Browse [Flask templates](https://vercel.com/templates/flask) you can deploy in one step
  
- Learn how [Vercel Functions](https://vercel.com/docs/functions) run your server code
  
- Understand the [Python runtime](https://vercel.com/docs/functions/runtimes/python), including versions, streaming, and bundling
  
- Understand pricing and scaling with [Fluid compute](https://vercel.com/docs/fluid-compute)
  
- Run code before requests with [Routing Middleware](https://vercel.com/docs/routing-middleware)
  
- Defer background work from your routes with [Vercel Queues](https://vercel.com/docs/queues), or orchestrate multi-step tasks with [Vercel Workflows](https://vercel.com/docs/workflows)

---

[View full KB sitemap](/kb/sitemap.md)
