devops beginner

Deploying Flask to Railway

min read Frederick Tubiermont

Deploying Flask to Railway

Railway is the fastest way to host a Flask + PostgreSQL app. You get managed PostgreSQL, automatic deployments from GitHub, and a generous free tier. This tutorial takes you from a working local app to a live URL.

What You Need Before Starting

  • Your Flask app running locally with python app.py
  • A requirements.txt with all your dependencies
  • A Railway account at railway.app (free)
  • Your code in a GitHub repository

Step 1: Add a Procfile

Railway needs to know how to start your app in production. Create a Procfile in your project root:

web: gunicorn app:app

app:app means: in app.py, run the app Flask object. Install gunicorn if you have not already:

pip install gunicorn
pip freeze > requirements.txt

Step 2: Test gunicorn Locally

Before deploying, confirm gunicorn starts your app correctly:

gunicorn app:app

Visit http://127.0.0.1:8000. If it works locally, it will work on Railway.

Step 3: Create a Railway Project

  1. Go to railway.app → New Project → Deploy from GitHub repo
  2. Select your repository
  3. Railway detects the Procfile and starts building

Your app will fail on first deploy — that is expected, because there is no database yet.

Step 4: Add a PostgreSQL Service

In your Railway project dashboard:

  1. Click NewDatabaseAdd PostgreSQL
  2. Railway provisions a managed PostgreSQL instance in seconds

Step 5: Get Your Database Credentials

Click your PostgreSQL service → Connect tab. You will see individual connection variables:

PGHOST     → copy this as DB_HOST
PGPORT     → copy this as DB_PORT
PGDATABASE → copy this as DB_NAME
PGUSER     → copy this as DB_USER
PGPASSWORD → copy this as DB_PASSWORD

Do not use the DATABASE_URL connection string — set each variable individually so your existing DB_CONFIG in app.py works without modification.

Step 6: Set Environment Variables

In your Flask service (not the PostgreSQL service) → Variables tab, add:

DB_HOST       = (value from PGHOST)
DB_PORT       = (value from PGPORT)
DB_NAME       = (value from PGDATABASE)
DB_USER       = (value from PGUSER)
DB_PASSWORD   = (value from PGPASSWORD)
SECRET_KEY    = (generate with: python -c "import secrets; print(secrets.token_hex(32))")
FLASK_ENV     = production
RESEND_API_KEY = (your Resend key, if used)

Your app will redeploy automatically after saving.

Step 7: Run Your Migration

To create tables on the Railway database, run your migration script against Railway's database from your local machine:

# Temporarily set env vars pointing to Railway DB
export DB_HOST=your-railway-host
export DB_PORT=your-railway-port
export DB_NAME=your-railway-db-name
export DB_USER=your-railway-user
export DB_PASSWORD=your-railway-password

python migrate.py

Or use the Railway CLI to run it directly on the server:

npm install -g @railway/cli
railway login
railway run python migrate.py

Step 8: Check Your Deployment

Railway shows build and runtime logs in the Deployments tab. Common issues:

Error Fix
ModuleNotFoundError Missing package in requirements.txt — run pip freeze > requirements.txt
Connection refused (DB) Wrong DB_HOST or DB_PORT — double-check from Railway Connect tab
gunicorn: not found Add gunicorn to requirements.txt
502 Bad Gateway App crashed on startup — check logs for traceback

Step 9: Add a Custom Domain

Railway provides a .up.railway.app URL by default. To use your own domain:

  1. Go to your service → SettingsDomainsCustom Domain
  2. Add your domain and follow the DNS instructions (typically a CNAME record)
  3. Railway provisions an SSL certificate automatically

Environment: Production vs Development

Make sure your Flask app does not run in debug mode in production:

if __name__ == "__main__":
    debug_mode = os.environ.get("FLASK_ENV") == "development"
    app.run(debug=debug_mode)

gunicorn ignores the app.run() call entirely — it manages its own workers. But this protects you if someone runs python app.py in production accidentally.

AI Prompt That Generated This

"Create a Procfile for a Flask app using gunicorn. Show how to set individual PostgreSQL environment variables (DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD) in Railway's dashboard from the Connect panel, without using DATABASE_URL. Include a checklist of common deployment errors."

Next Steps

  • Set up GitHub Actions to run pytest tests before every deploy
  • Add Rate Limiting with a Redis service on Railway for distributed limits

Was this helpful?

Get More Flask Vibe Tutorials

Join 1,000+ developers getting weekly Flask tips and AI-friendly code patterns.

No spam. Unsubscribe anytime.