Building a Scalable Django Project Structure (Step by Step Guide)
Suresh Thapa
Building a Scalable Django Project Structure (Step by Step Guide)
When you start a Django project, it’s tempting to keep everything inside a single settings.py file and clutter your root folder with configurations. This works for toy projects, but it quickly becomes painful when you scale to production.
A scalable Django structure looks like this:
ZeroTrustSpace/
├── config/
│ ├── __init__.py
│ ├── urls.py
│ ├── wsgi.py
│ └── settings/
│ ├── __init__.py
│ ├── base.py
│ ├── local.py
│ └── production.py
├── manage.py
Why this structure?
- Separation of concerns → Base settings for all environments, with overrides for local development and production.
- Clarity → All config lives in a single
config/directory. - Scalability → Easy to extend with more apps and environments.
- Maintainability → No spaghetti
settings.py.
Step 1: Create the project
django-admin startproject config .
Then rename the outer project folder to your project name (ZeroTrustSpace/) and keep config/ as the inner config directory.
Step 2: Split your settings
Inside config/settings/:
base.py
Contains settings shared across all environments.
from pathlib import Path
import os
BASE_DIR = Path(__file__).resolve().parent.parent.parent
SECRET_KEY = os.getenv("DJANGO_SECRET_KEY", "insecure-secret")
DEBUG = False
ALLOWED_HOSTS = ["*"]
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# your apps here
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "config.urls"
WSGI_APPLICATION = "config.wsgi.application"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
STATIC_URL = "/static/"
MEDIA_URL = "/media/"
local.py
For development only.
from .base import *
DEBUG = True
ALLOWED_HOSTS = ["*"]
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
production.py
For production deployment.
from .base import *
DEBUG = False
ALLOWED_HOSTS = ["zerotrustspace.com"]
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.getenv("POSTGRES_DB"),
"USER": os.getenv("POSTGRES_USER"),
"PASSWORD": os.getenv("POSTGRES_PASSWORD"),
"HOST": os.getenv("POSTGRES_HOST", "localhost"),
"PORT": os.getenv("POSTGRES_PORT", "5432"),
}
}
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
Step 3: Configure WSGI and manage.py
Both files must know which settings to load.
config/wsgi.py
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
application = get_wsgi_application()
manage.py
#!/usr/bin/env python
import os
import sys
def main():
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()
Step 4: Add .env support (optional but recommended)
Install django-environ:
pip install django-environ
Update base.py:
import environ
env = environ.Env()
environ.Env.read_env(os.path.join(BASE_DIR, ".env"))
SECRET_KEY = env("DJANGO_SECRET_KEY", default="unsafe-secret")
Create .env:
DJANGO_SECRET_KEY=super-secret-key
POSTGRES_DB=zerotrustspace
POSTGRES_USER=postgres
POSTGRES_PASSWORD=password123
Step 5: Add new apps in apps/
Instead of dumping apps in the root, create an apps/ folder:
ZeroTrustSpace/
├── apps/
│ ├── blog/
│ │ ├── __init__.py
│ │ ├── models.py
│ │ ├── views.py
│ │ └── urls.py
Update INSTALLED_APPS in base.py:
INSTALLED_APPS += ["apps.blog"]
Benefits
- Easy to maintain
- Clean separation between environments
- Production-ready with PostgreSQL + environment variables
- Extensible for Docker, CI/CD, multi-app projects
With this setup, you’re already ahead of 90% of beginner Django devs.