# How to deploy a uv project to Vercel


Vercel installs Python dependencies with [uv](https://pydevtools.com/handbook/reference/uv.md) by default, with no configuration, and it reads a [uv.lock](https://pydevtools.com/handbook/explanation/what-is-a-lock-file.md) natively. Deploying a uv project is mostly committing the lockfile and giving Vercel an entrypoint it recognizes. This guide covers the entrypoint, the lockfile-priority trap that breaks builds, pinning the Python version, and keeping the bundle under Vercel's 500 MB limit.

## Give Vercel an entrypoint it recognizes

Vercel loads one top-level variable from a Python file as the function handler. The file must define one of three names:

- `app` for most ASGI or WSGI frameworks, including FastAPI and Flask
- `application` for Django and other WSGI applications
- `handler` for serverless functions that subclass `BaseHTTPRequestHandler`

Vercel auto-detects an entrypoint named `app.py`, `index.py`, `server.py`, `main.py`, `wsgi.py`, or `asgi.py` at the project root or inside `src/`, `app/`, or `api/`. A FastAPI app at the root needs no configuration:

```python {filename="app.py"}
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def home():
    return {"message": "Hello from uv on Vercel"}
```

For a plain serverless function with no framework, drop a file in `/api`. Each `.py` file there that defines a `handler` becomes its own Vercel Function:

```python {filename="api/index.py"}
from http.server import BaseHTTPRequestHandler


class handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/plain")
        self.end_headers()
        self.wfile.write(b"Hello from uv on Vercel")
```

Declare the dependency in `pyproject.toml` so it lands in the lockfile:

```bash
uv add fastapi
```

## Deploy straight from the lockfile

Lock the project and commit both manifests. Vercel installs the exact versions in `uv.lock` with uv during the build:

```bash
uv lock
git add pyproject.toml uv.lock app.py
git commit -m "Add Vercel entrypoint"
```

Deploy with the Vercel CLI. A bare `vercel` creates a preview deployment; `--prod` targets production:

```bash
npm i -g vercel
vercel --prod
```

Vercel detects the framework from the dependency manifest, installs the locked dependencies with uv, and serves the entrypoint. The common case needs no `requirements.txt`, build hook, or install command override.

## Avoid the pyproject and requirements.txt conflict

A repository that carries both a `pyproject.toml` and a `requirements.txt` with no lockfile is the one shape that breaks. Vercel's uv-based installer prefers `pyproject.toml`, and if that file does not list the dependencies the old `requirements.txt` did, the build can install nothing and fail at runtime ([vercel/vercel issue #14041](https://github.com/vercel/vercel/issues/14041)).

Commit a `uv.lock` so `pyproject.toml` is the authoritative, complete source:

```bash
uv lock
git add uv.lock
```

If you would rather keep a single `requirements.txt`, delete the `pyproject.toml` from what Vercel builds, or generate the requirements file from uv and remove the project metadata Vercel would otherwise pick up. Pick one manifest and make it complete.

## Pin the Python version

Vercel defaults to Python 3.12 and also offers 3.13 and 3.14. It reads the version from `requires-python` in `pyproject.toml` or from a `.python-version` file. The `requires-python` floor is a lower bound, so `>=3.12` can resolve to a newer default as Vercel moves it forward.

Pin an exact runtime with uv, which writes the `.python-version` file Vercel reads:

```bash
uv python pin 3.12
git add .python-version
```

The [`.python-version` file](https://pydevtools.com/handbook/explanation/what-is-a-python-version-file.md) keeps the deployed runtime fixed regardless of where Vercel sets its default. To change versions later, see [How to change the Python version of a uv project](https://pydevtools.com/handbook/how-to/how-to-change-the-python-version-of-a-uv-project.md).

## Keep the function bundle under 500 MB

Python functions have a 500 MB uncompressed bundle limit, and Vercel does no tree-shaking: everything reachable at build time ships. Two levers keep the bundle small.

Strip dev-only tools by exporting a runtime-only requirements file. Vercel's lockfile install carries whatever your project resolves; exporting with `--no-dev` guarantees [pytest](https://pydevtools.com/handbook/reference/pytest.md), [Ruff](https://pydevtools.com/handbook/reference/ruff.md), and their transitive dependencies stay out of the deploy:

```bash
uv export --frozen --no-dev --no-emit-project -o requirements.txt
```

`--no-emit-project` excludes the project itself, which Vercel installs from source anyway, and `--no-dev` drops the dev dependency groups. On a FastAPI project with `pytest` and `ruff` in the dev group, this cut the exported file from 155 to 113 lines. Commit the generated `requirements.txt` as your single manifest and remove `pyproject.toml` from the build to avoid the conflict above.

Drop tests, fixtures, and static assets with `excludeFiles` in `vercel.json`, a glob relative to the project root:

```json {filename="vercel.json"}
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "functions": {
    "api/**/*.py": {
      "excludeFiles": "{tests/**,**/test_*.py,fixtures/**,static/**}"
    }
  }
}
```

Vercel builds and installs in its own Linux environment, so wheels for packages with C or Rust extensions resolve for the right platform automatically. That avoids the cross-build flags a local-install target like [AWS Lambda](https://pydevtools.com/handbook/how-to/how-to-deploy-a-uv-project-to-aws-lambda.md) requires.

## Learn more

- [Using the Python Runtime with Vercel Functions](https://vercel.com/docs/functions/runtimes/python) documents entrypoints, dependency files, and the 500 MB limit.
- [Python package manager uv is now available for builds with zero configuration](https://vercel.com/changelog/python-package-manager-uv-is-now-available-for-builds-with-zero) is the October 2025 changelog that made uv the default.
- [Set the Python version for your Vercel project](https://vercel.com/docs/functions/runtimes/python/python-version) covers `requires-python` and `.python-version` selection.
- [uv: A Complete Guide](https://pydevtools.com/handbook/explanation/uv-complete-guide.md) covers what uv does, how fast it is, and the core workflows.
- [How to deploy a uv project to AWS Lambda](https://pydevtools.com/handbook/how-to/how-to-deploy-a-uv-project-to-aws-lambda.md) applies the same lockfile discipline to a serverless target that installs locally.
