How to Deploy a Flask App to Production (Gunicorn + PostgreSQL, 2026)
Take Flask from app.run() to production: Gunicorn, configuration from the environment, PostgreSQL with Flask-SQLAlchemy, migrations and a live HTTPS URL.
- Published
- Reading time
- 3 min
On this page
Key takeaways
- Never use Flask's built-in server (app.run) in production: run under Gunicorn, which DockHosting does for you.
- Load SECRET_KEY and DATABASE_URL from the environment; Flask-SQLAlchemy reads DATABASE_URL directly.
- The default start command is gunicorn app:app, and you can override it if your app object lives elsewhere.
Flask's development server prints a warning for a reason: it's for your laptop. In production you want a real WSGI server, configuration from the environment, and a database that isn't SQLite on a disk that disappears. Here's the whole path to a live HTTPS URL.
1. Structure the app
# app.py
import os
from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SECRET_KEY"] = os.environ["SECRET_KEY"]
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ["DATABASE_URL"].replace(
"postgresql://", "postgresql+psycopg://", 1
)
db = SQLAlchemy(app)
class Note(db.Model):
id = db.Column(db.Integer, primary_key=True)
text = db.Column(db.String(500), nullable=False)
@app.get("/health")
def health():
return {"status": "ok"}
@app.get("/notes")
def notes():
return jsonify([{"id": n.id, "text": n.text} for n in Note.query.all()])The replace call selects the psycopg 3 driver for SQLAlchemy.
# requirements.txt
flask
flask-sqlalchemy
flask-migrate
gunicorn
psycopg[binary]2. Gunicorn, configured for you
DockHosting detects Flask from flask in your requirements and runs it under Gunicorn:
gunicorn app:appThat's module:variable. If you use an application factory, point Gunicorn at it by overriding the start command in the project settings:
gunicorn "myapp:create_app()" --workers 2 --bind 0.0.0.0:$PORTTwo workers per 512 MB is a safe start. Each worker is a full copy of your app in memory.
3. Migrations with Flask-Migrate
flask --app app db init # once, locally
flask --app app db migrate -m "notes table"Commit the migrations/ folder, and apply migrations on each release as part of the start command:
flask --app app db upgrade && gunicorn app:app4. Deploy
curl -fsSL https://cli.dockhosting.dev/install.sh | sh # Windows: irm https://cli.dockhosting.dev/install.ps1 | iex
dock login
dock deployThen:
- Create a managed PostgreSQL database and attach it.
DATABASE_URLis injected over the private network. - Set
SECRET_KEYin the environment variables (python -c "import secrets; print(secrets.token_hex(32))"). dock restart, then openhttps://<project>.dockhosting.cloud/health.
5. Production checklist
SECRET_KEYcomes from the environment, never from the code.- Debug is off, and
app.run()isn't called at import time. - Gunicorn workers are sized to your plan's memory (512 MB on Free, 1 GB on Hobby).
- Static files are served from
static/or a CDN for heavy assets. - A
/healthroute makes failed deploys obvious.
Seeing 502s? Work through the 8 causes of a 502. Building a larger app? Compare with the Django and FastAPI guides.
Frequently asked questions
Do I need a Procfile to deploy Flask?
No. DockHosting detects Flask from your requirements and runs it under Gunicorn (gunicorn app:app by default). If your app is created elsewhere, for example by a factory in wsgi.py, override the start command in the project settings.
Why does Flask say 'WARNING: This is a development server'?
Because app.run() starts Werkzeug's development server, which isn't built for production traffic or security. Use Gunicorn instead.
Which Python versions are supported?
Python 3.11 and 3.12, with pip (requirements.txt) or Poetry (pyproject.toml).
- Flask
- Python
- Gunicorn
- PostgreSQL
- Tutorial
Written by Doughmi ILYAS
Doughmi builds DockHosting, the developer-first platform behind dock deploy: the build system, the managed databases and the dashboard. On this blog: guides to shipping apps without running servers, written with the commands the platform actually ships.
