Back to Blog
Guide8 min read2026-05-01

Python Web App Production Deployment: Flask, Django, FastAPI

A practical guide to deploying Python web applications — Flask, Django, and FastAPI — to production with Docker, the right WSGI/ASGI server, and a cloud PaaS.

Python Web App Production Deployment: Flask, Django, FastAPI

Python has three dominant web frameworks: Flask for minimal APIs, Django for full-stack applications, and FastAPI for high-performance async services. Each has different production requirements — particularly around their server stack. This guide covers how to deploy all three correctly on [PandaStack](https://pandastack.io).

Choosing the Right Server

Python web frameworks are not standalone servers. They implement either WSGI (Web Server Gateway Interface) or ASGI (Asynchronous Server Gateway Interface) and require an application server to handle HTTP:

FrameworkInterfaceRecommended Server
FlaskWSGIGunicorn
DjangoWSGIGunicorn
FastAPIASGIUvicorn + Gunicorn

Never run flask run, python manage.py runserver, or uvicorn main:app --reload in production — these are development servers only.

Flask Production Setup

# app.py
from flask import Flask, jsonify
import os

app = Flask(__name__)

@app.route('/health')
def health():
    return jsonify({'status': 'ok'}), 200

@app.route('/api/items')
def get_items():
    return jsonify({'items': []})

if __name__ == '__main__':
    # Only for local development
    app.run(debug=True)
# Dockerfile for Flask
FROM python:3.12-slim

WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser
USER appuser

EXPOSE 8000

CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000", "--workers", "4", "--timeout", "30"]
# requirements.txt for Flask
flask>=3.0.0
gunicorn>=21.2.0
psycopg2-binary>=2.9.0
flask-sqlalchemy>=3.1.0

Django Production Setup

# Dockerfile for Django
FROM python:3.12-slim

WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV DJANGO_SETTINGS_MODULE=myproject.settings.production

RUN apt-get update && apt-get install -y --no-install-recommends     libpq-dev build-essential     && rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .
RUN python manage.py collectstatic --noinput

EXPOSE 8000

CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3"]

FastAPI Production Setup

# Dockerfile for FastAPI
FROM python:3.12-slim

WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["gunicorn", "main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:8000"]

FastAPI requires the Uvicorn worker class to handle async requests correctly through Gunicorn's process manager.

Shared pandastack.json Pattern

All three frameworks follow the same pandastack.json pattern — container deployment with a health check path:

{
  "type": "container",
  "healthCheckPath": "/health"
}

Implement the /health endpoint in each framework to return HTTP 200. PandaStack polls this endpoint after every deployment and only routes traffic to the container once it responds successfully.

Gunicorn Worker Count

The standard formula for Gunicorn workers:

workers = (2 × CPU_cores) + 1

For most PandaStack containers (2 vCPU), start with -w 5. Adjust based on memory usage — each Gunicorn worker is a separate Python process.

# Gunicorn command with recommended settings
gunicorn app:app   --bind 0.0.0.0:8000   --workers 5   --timeout 30   --keepalive 5   --access-logfile -   --error-logfile -

Logging to - (stdout/stderr) lets PandaStack capture your logs in the dashboard.

Environment Variables

All three frameworks should read configuration from environment variables. Set them in [dashboard.pandastack.io](https://dashboard.pandastack.io):

# Common across Flask, Django, FastAPI
DATABASE_URL=postgresql://user:pass@host:5432/mydb
REDIS_URL=redis://redis.internal:6379
SECRET_KEY=your-application-secret

# Django-specific
DJANGO_SETTINGS_MODULE=myproject.settings.production
ALLOWED_HOST=yourdomain.com

# Flask-specific
FLASK_ENV=production

Provisioning Databases

PandaStack provides managed PostgreSQL, MySQL, Redis, and MongoDB databases. Provision from the Databases section at [dashboard.pandastack.io](https://dashboard.pandastack.io) and use the connection string in DATABASE_URL.

Connect with the appropriate library for your framework:

# Flask + SQLAlchemy
from flask_sqlalchemy import SQLAlchemy
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DATABASE_URL']

# Django
DATABASES = {'default': {'ENGINE': 'django.db.backends.postgresql', 'NAME': ...}}

# FastAPI + asyncpg
import databases
database = databases.Database(os.environ['DATABASE_URL'])

GitHub Integration and Deployment

Connect your GitHub repository from the PandaStack dashboard. Every push to your deployment branch triggers an automatic Docker build and deploy. For manual or scripted deploys:

npm install -g @pandastack/cli
panda deploy

Production Checklist (All Frameworks)

  • Gunicorn (or Gunicorn + Uvicorn worker for FastAPI) is the application server
  • DEBUG / FLASK_DEBUG is off in production
  • All secrets are environment variables — no hardcoded values
  • /health returns HTTP 200 and is specified in pandastack.json
  • Logs output to stdout/stderr
  • Database connection uses a pool, not individual connections
  • Static files handled by framework (WhiteNoise for Django, Flask-Static for Flask)
  • GitHub integration connected for automatic deploys

Visit [docs.pandastack.io](https://docs.pandastack.io) for the full deployment documentation.

Ready to deploy?

Start free on PandaStack — no credit card required.

Start free on PandaStack

More in Guide

Browse all Guide articles →

See also