NANDHOO.

Deployment & Beyond


Building code on your local machine is only the beginning. Deployment means making your Python application available to the world — reliably, securely, and repeatedly. This chapter covers how to prepare Python projects for production and what to learn next.


Why This Chapter Matters


The best code that only runs on your laptop provides no value. Deployment is how your work reaches real users. Understanding the basics of packaging, environment configuration, containerization, and hosting is essential for any serious Python developer.


Development vs Production


AspectDevelopmentProduction
ErrorsVerbose, helpfulLogged privately, generic to users
SettingsDebug on, local DBDebug off, production DB
SpeedNot criticalOptimized and monitored
SecurityRelaxedHardened
RestartsManualAutomatic (process manager)

Environment Configuration


Use environment variables (not hard-coded values) for all configuration.


.env file (never commit this!)


DATABASE_URL=postgresql://user:password@host/dbname
SECRET_KEY=super-secret-value-here
DEBUG=false
PORT=8000

Loading .env in Python


pip install python-dotenv

import os
from dotenv import load_dotenv

load_dotenv()


DATABASE_URL = os.environ.get("DATABASE_URL") DEBUG = os.environ.get("DEBUG", "false").lower() == "true" PORT = int(os.environ.get("PORT", 8000))


Using a Config Class


from pydantic_settings import BaseSettings

class Settings(BaseSettings): database_url: str secret_key: str debug: bool = False port: int = 8000


class Config:
    env_file = ".env"

settings = Settings() print(settings.database_url)


Packaging Your Application


requirements.txt


pip freeze > requirements.txt

Always pin exact versions in production:


fastapi==0.111.0
uvicorn==0.29.0
pydantic==2.7.0
sqlalchemy==2.0.29

pyproject.toml (Modern Approach)


[project]
name = "myapp"
version = "1.0.0"
requires-python = ">=3.11"
dependencies = [
    "fastapi>=0.111.0",
    "uvicorn>=0.29.0",
]

Docker — Containerization


Docker packages your app and all its dependencies into a container that runs identically everywhere.


Dockerfile for a FastAPI App


FROM python:3.12-slim

WORKDIR /app


Copy and install dependencies first (layer caching)

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


Copy application code

COPY . .


Expose the port

EXPOSE 8000


Run the app

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]


.dockerignore


venv/
__pycache__/
.env
*.pyc
.git/

Build and Run


docker build -t myapp .
docker run -p 8000:8000 --env-file .env myapp

Docker Compose (Multiple Services)


version: "3.9"
services:
  api:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db/mydb
    depends_on:
      - db

db: image: postgres:15 environment: POSTGRES_USER: user POSTGRES_PASSWORD: pass POSTGRES_DB: mydb volumes: - postgres_data:/var/lib/postgresql/data


volumes: postgres_data:


docker-compose up --build

Deployment Platforms


Cloud Platforms (PaaS)


PlatformBest For
RailwaySimple FastAPI / Django apps
RenderFree tier web services
Fly.ioDocker containers, global regions
HerokuClassic PaaS, Procfile-based
VercelServerless Python functions

Cloud Providers (IaaS)


ProviderService
AWSEC2, ECS, Lambda, App Runner
Google CloudCloud Run, GKE, App Engine
AzureApp Service, Container Apps

Deploying to Railway (Simple Example)


  1. Create a Procfile:
web: uvicorn main:app --host 0.0.0.0 --port $PORT
  1. Push to GitHub
  2. Connect the repo in Railway
  3. Set environment variables in the Railway dashboard
  4. Deploy

Process Management


In production, use a process manager to keep your app running and restart it on crashes.


Gunicorn + Uvicorn Workers (Production ASGI)


pip install gunicorn
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000

  • -w 4: 4 worker processes
  • -k uvicorn.workers.UvicornWorker: use Uvicorn's ASGI worker

Systemd (Linux Servers)


[Unit]
Description=FastAPI App
After=network.target

[Service] User=www-data WorkingDirectory=/app ExecStart=/app/venv/bin/gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker Restart=always


[Install] WantedBy=multi-user.target


Health Checks & Logging


Always add a health check endpoint:


@app.get("/health")
def health():
    return {"status": "ok", "version": "1.0.0"}

Set up structured logging:


import logging

logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s" )


logger = logging.getLogger(name) logger.info("Application started")


Database Migrations Before Deployment


Always run migrations before starting the server:


# Alembic migrations
alembic upgrade head

In Docker Compose, use a startup script:


#!/bin/sh
alembic upgrade head
uvicorn main:app --host 0.0.0.0 --port 8000

CI/CD — Automated Testing and Deployment


CI/CD (Continuous Integration / Continuous Deployment) runs tests automatically and deploys when tests pass.


GitHub Actions Example


name: Test and Deploy

on: push: branches: [main]


jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.12" - run: pip install -r requirements.txt - run: pytest


deploy: needs: test runs-on: ubuntu-latest steps: - name: Deploy to Railway run: railway up


What to Learn Next


After mastering these 16 chapters, the Python ecosystem offers much more:


TopicTools
Web developmentDjango, Flask, Starlette
Data scienceScikit-learn, Seaborn, SciPy
Machine learningPyTorch, TensorFlow, Keras
Data pipelinesAirflow, Prefect, dbt
Type checkingmypy, pyright
CLI toolsTyper, Click, argparse
Task queuesCelery, RQ, ARQ
GraphQLStrawberry
WebSocketsFastAPI WebSockets, channels

Common Mistakes


  • committing .env files to version control
  • running the development server (--reload) in production
  • deploying without running tests first
  • hard-coding ports and secrets instead of using environment variables
  • not setting up health checks or logging in production
  • not pinning exact dependency versions in requirements.txt

Mini Exercises


  1. Add a /health endpoint to a FastAPI app and test it.
  2. Create a Dockerfile for a simple Python script, build it, and run it.
  3. Write a .env file with at least 3 settings and load them with python-dotenv.
  4. Create a docker-compose.yml that ties your app to a PostgreSQL container.
  5. Write a GitHub Actions workflow that runs pytest on every push.

Review Questions


  1. What is the difference between development and production environments?
  2. Why should you never commit a .env file to version control?
  3. What problem does Docker solve for deploying Python apps?
  4. What is the purpose of Gunicorn when running a FastAPI app in production?
  5. What is CI/CD and why is it valuable?

Reference Checklist


  • I can configure apps using environment variables and .env files
  • I can write a Dockerfile for a Python web application
  • I can use Docker Compose to run multi-service apps locally
  • I know the most common Python deployment platforms
  • I understand the role of process managers like Gunicorn
  • I know how to set up basic CI/CD with GitHub Actions

Back to Python Course Overview