How to Deploy a Django App to Production in 2025



This content originally appeared on DEV Community and was authored by Piko

From Localhost to Live: The Essential Django Deployment Guide

You’ve done it. You’ve built a Django app, and it’s running beautifully on your local machine with its virtual environment and all dependencies installed. Now comes the big question: how do you get this thing ready for the world to see?

Deploying a Django app isn’t just about copying files to a server. It’s about transforming your development setup into a secure, efficient, and reliable production environment. This guide will walk you through the essential steps to bridge that gap.

The Golden Rule: Never Hardcode Secrets

Before we touch anything, let’s establish the most important principle: separate your configuration from your code. Your production environment will have different settings than your local one (different databases, secret keys, debug settings). Hardcoding these values is a recipe for security risks and deployment headaches.

The solution is to use environment variables. We’ll store our configuration in the hosting environment and have Django read from there.

For local development, we can simulate this with a .env file and the python-dotenv library.

  1. Install the library:

    pip install python-dotenv
    
  2. Create a .env file in your project’s root (the same level as manage.py):

    # .env
    DEBUG=True
    SECRET_KEY=your-insecure-local-secret-key
    DATABASE_URL=sqlite:///db.sqlite3
    

    Important: Add .env to your .gitignore file immediately! This file should never be committed to version control.

Step 1: Production-Proof Your settings.py

Now, let’s modify your settings.py to read from these environment variables.

1.1 Load Environment Variables

At the top of your settings.py, add the following to load the .env file (it won’t do anything in production, which is what we want).

# settings.py
import os
from dotenv import load_dotenv

load_dotenv()

1.2 Secure SECRET_KEY and DEBUG

Replace your hardcoded SECRET_KEY and DEBUG values.

# settings.py

# Pull the SECRET_KEY from the environment
SECRET_KEY = os.getenv("SECRET_KEY")

# Set DEBUG to False unless explicitly set to "True" in the environment
DEBUG = os.getenv("DEBUG", "False").lower() == "true"

1.3 Configure ALLOWED_HOSTS

In production, you must tell Django which domain(s) are permitted to host your app.

# settings.py

# We'll get the actual domain from our hosting provider later
ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "localhost,127.0.0.1").split(",")

# Important for security when running on HTTPS
CSRF_TRUSTED_ORIGINS = os.getenv("CSRF_TRUSTED_ORIGINS", "http://localhost").split(",")

Step 2: Bring in the Production Stack

Your development server and database aren’t cut out for production traffic. Let’s bring in the right tools for the job.

2.1 Use a Production WSGI Server: Gunicorn

The manage.py runserver command is only for development. For production, you need a robust WSGI server. Gunicorn (Green Unicorn) is a popular and reliable choice.

pip install gunicorn

2.2 Serve Static Files with WhiteNoise

When DEBUG is False, Django stops serving static files (your CSS, JavaScript, and images). WhiteNoise is the easiest way to get your app to serve its own static files securely and efficiently.

  1. Install WhiteNoise:

    pip install whitenoise
    
  2. Configure in settings.py:

    • Add WhiteNoise to your middleware, right after the SecurityMiddleware.
    • Set the STATIC_ROOT and configure the staticfiles storage backend.
    # settings.py
    
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'whitenoise.middleware.WhiteNoiseMiddleware', # Add this line
        # ... other middleware
    ]
    
    # This is where collectstatic will gather all static files
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
    
    # This improves performance by caching and compressing files
    STORAGES = {
        "staticfiles": {
            "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
        },
    }
    

2.3 Switch to a Production Database: PostgreSQL

SQLite is a single-file database that can’t handle concurrent requests well, making it unsuitable for most production sites. PostgreSQL is a powerful, open-source database that’s a standard choice for Django apps.

To make connecting easy, we’ll use dj-database-url and psycopg2-binary.

  1. Install Packages:

    pip install psycopg2-binary dj-database-url
    
  2. Configure in settings.py:
    This will read your database connection string from a single DATABASE_URL environment variable. It cleverly defaults to your existing SQLite setup if the variable isn’t found.

    # settings.py
    import dj_database_url
    
    # ... at the bottom of the file ...
    
    DATABASES = {
        'default': dj_database_url.config(
            # Default to SQLite if DATABASE_URL is not set
            default=f"sqlite:///{os.path.join(BASE_DIR, 'db.sqlite3')}"
        )
    }
    

Step 3: Automate Your Deployment Tasks

You need to perform the same set of tasks every time you deploy: install packages, collect static files, and run migrations. Let’s automate this with a simple build script.

Create a file named build.sh in your project’s root:

#!/bin/bash

# Exit immediately if a command exits with a non-zero status.
set -e

# Install Python dependencies
pip install -r requirements.txt

# Run Django's collectstatic to gather static files
python manage.py collectstatic --no-input

# Apply any database migrations
python manage.py migrate

Now, make the script executable: chmod +x build.sh

Final Preparations

You’re almost there!

  1. Update requirements.txt: Your virtual environment now has Gunicorn, WhiteNoise, and other production packages. Update your requirements file to reflect this.

    pip freeze > requirements.txt
    
  2. Push to Git: Commit all your changes and push them to your GitHub (or GitLab) repository. Your code is now fully prepared for deployment.

Time to Deploy!

Now you can head to your hosting platform of choice (like Seenode, Heroku, Render, etc.). The process will generally be:

  1. Connect Your Repo: Link the platform to your GitHub repository.
  2. Set Build & Start Commands:
    • Build Command: ./build.sh
    • Start Command: gunicorn movie_spot.wsgi --bind 0.0.0.0:80 (Replace movie_spot with your project’s name).
  3. Set Environment Variables: This is where you’ll add your production SECRET_KEY, set DEBUG to False, and provide the DATABASE_URL from the PostgreSQL database you create on the platform. You’ll also set your live domain in ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS.

And that’s it! With these steps, you’ve taken your Django project from a local development build to a secure, robust, and production-ready application.

Are you a visual learner?

I’ve created a complete video walkthrough of this deployment guide. Watch and code along as we take our project from localhost to a live, production-ready application on the cloud.

Django Deployment Tutorial: From Local Setup to Live Server on Seenode | Beginner Friendly Guide<br>

Happy deploying


This content originally appeared on DEV Community and was authored by Piko