Deploy Django on Vercel (and Its Limits)
Deploy a Django app on Vercel’s Python runtime: expose the WSGI app, collect static files at build time, use an external PostgreSQL such as Neon, and understand what serverless Django on Vercel cannot do.
Problem statement
Vercel is best known for frontend frameworks, but its Python runtime can serve a WSGI app such as Django as serverless functions. For a small Django site, an API backing a Next.js frontend on the same platform, or a demo, that means git-push deploys, preview URLs per branch, and no servers. The model has real limits for Django, though: no persistent filesystem, no background workers, per-invocation time limits, and database connections opened from many short-lived instances. This guide shows a working setup and is explicit about when to choose a container platform instead.
- Expose Django's WSGI application as
appin the entry file Vercel's Python runtime uses (for exampleapi/index.pyimportingconfig.wsgi.application). - Add a
vercel.jsonthat routes all paths to that function, and list dependencies inrequirements.txt. - Use an external PostgreSQL with pooling (Neon, Supabase, or another provider's pooled endpoint); never SQLite.
- Run
collectstaticduring the build and serve static files with WhiteNoise or as Vercel static output. - Store media uploads in S3-compatible storage.
- Move background jobs and long requests elsewhere; Vercel functions have execution time limits.
Step-by-step solution
1. Expose the WSGI app
Vercel's Python runtime looks for a variable named app (a WSGI or ASGI callable) in function files. Create an entry point:
# api/index.py
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
from config.wsgi import application as app # noqa: E402
Route every path to it:
{
"rewrites": [{ "source": "/(.*)", "destination": "/api/index" }]
}
Vercel's Python support has evolved quickly, including framework detection; check the current Vercel documentation for the exact entry-point conventions and supported Python versions before relying on this layout.
2. Configure settings for serverless
DEBUG = False
ALLOWED_HOSTS = [".vercel.app", "example.com"]
CSRF_TRUSTED_ORIGINS = ["https://*.vercel.app", "https://example.com"]
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
DATABASES = {"default": env.db("DATABASE_URL")}
DATABASES["default"]["CONN_MAX_AGE"] = 0
Set SECRET_KEY, DATABASE_URL, and storage credentials as Vercel environment variables, separately for Production and Preview so preview deployments never touch production data.
3. Use an external, pooled database
Each function instance opens its own connection, and bursts create many instances. Use a provider with a connection pooler (Neon's pooled endpoint, Supabase's pooler, or PgBouncer in front of your own database) and keep CONN_MAX_AGE = 0. Choose a database region close to the Vercel function region to keep query latency low.
Run migrations from CI or your machine against the production database, not during the Vercel build, so a failed build cannot leave the schema half migrated.
4. Static files
Run collectstatic in the build:
{
"buildCommand": "python manage.py collectstatic --noinput",
"rewrites": [{ "source": "/(.*)", "destination": "/api/index" }]
}
WhiteNoise then serves the collected files from the function bundle, or configure the static output so Vercel's CDN serves /static/ directly without invoking Python.
5. Media and background work
Use django-storages with S3, R2, or Vercel Blob through an S3-compatible client for uploads. For background tasks, call a queue service (for example a hosted Redis with RQ workers on another platform, or an HTTP-based job service) and keep request handlers short.
Verification check: open the production URL and a preview URL, confirm both work and use different databases, check that /static/admin/css/base.css returns 200 with cache headers, and watch function duration and cold starts in Vercel's logs.
Explanation
Vercel's Python runtime packages your code into serverless functions and invokes them per request, translating HTTP events into WSGI calls for Django. That gives automatic scaling and zero idle cost, but no process lives long enough for connection pools, in-process caches, or background threads, and nothing written to disk survives. Django handles this well when state is externalised. It fits poorly when the app relies on workers, schedulers, WebSockets, or long-running requests, all of which are first-class on container platforms.
Edge cases / notes
- Bundle size. Python functions have size limits; heavy dependencies (scientific stacks, GDAL) may not fit.
- Cold starts add latency to the first request on a new instance; keep import-time work small.
- Admin uploads must stay under the request body limit for functions; upload large files directly to storage.
- Region. Pin functions to one region near your database rather than running everywhere.
Next steps
- Compare with a container platform: Deploy Django on Render.
- For AWS-based serverless, see Deploy Django to AWS Lambda.
FAQ
Can Django run on Vercel?
Yes, through the Python runtime as serverless functions, with an external database and object storage.
Can I run Celery on Vercel?
No. Vercel runs request-driven functions. Run workers on another platform.
Which database should I use with Django on Vercel?
A managed PostgreSQL with connection pooling, in a region close to your functions.
Is Vercel a good choice for Django?
For small sites and APIs without background workers, it can be. For full Django stacks, container platforms are simpler.