How to Split Django settings.py

Splitting django settings into multiple files with varying responsibilities enhances readability and maintainability, especially in very large and complex projects.

Splitting Django’s settings.py is one of the most valuable structural upgrades you can make. For small tutorials, a single settings file is fine.

For real projects, having one file eventually becomes painful: - development vs production differences - secrets handling - test config - Channels / Celery / Redis variants - cloud storage config - logging complexity - growing technical debt

This article explains two correct ways to split settings: 1. Right after starting a new Django project 2. After the project already exists

Both approaches matter, because the migration path is different.

Why Split Settings at All?

A single file usually becomes: settings.py # 800+ lines

Containing: - dev config - prod config - debug flags - test overrides - secrets - database switching - duplicated conditionals

That becomes hard to read and manage as the file becomes larger and containes either overlapping or mutuall exclusive responsibilities

Split settings create:

main/settings/
    base.py
    dev.py
    prod.py
    test.py

Benefits: - cleaner separation - safer production config - easier onboarding - better CI/CD - easier local development - scalable architecture

project/
    manage.py

    main/
        __init__.py
        asgi.py
        wsgi.py
        urls.py

        settings/
            __init__.py
            base.py
            dev.py
            prod.py
            test.py
bash

1

Part 1 — Split Settings Right After Project Start

This is the easiest time to do it.

Step 1: Create Project Normally

text

1
django-admin startproject main .

Default result:

main/
    settings.py
    urls.py
    asgi.py
    wsgi.py

Step 2: Convert settings.py into a Package

Inside main/:

Create directory:

text

1
main/settings/

Then create:

python

1
2
3
4
5
main/settings/__init__.py
main/settings/base.py
main/settings/dev.py
main/settings/prod.py
main/settings/test.py

Step 3: Move Existing Content to base.py

Everything from original settings.py goes into: main/settings/base.py

Except for the lines that will go into dev(Step4) and prod (Step 5)

Step 4: Create dev.py

python

1
2
3
4
from .base import *

DEBUG = True
ALLOWED_HOSTS = ["*"]

Step 5: Create prod.py

python

1
2
3
4
5
from .base import *

DEBUG = False
ALLOWED_HOSTS = ["example.com"]
SECURE_SSL_REDIRECT = True

Step 6: Update manage.py

Change: main.settings

to: main.settings.dev -> when developing main.settings.prod -> when switching to production

Example:

text

1
2
3
4
os.environ.setdefault(
    "DJANGO_SETTINGS_MODULE",
    "main.settings.dev"
)

Step 7: Update wsgi.py

Usually production: main.settings.prod

Step 8: Update asgi.py

Use desired environment.

For new projects, this takes minutes.

Why Doing It Early Is The Best Approach: - No legacy imports like: - from main.settings import SOME_VAR - No deployment assumptions. - No migration complexity.

Part 2 — Splitting Settings After Project Already Exists

This is common in real projects. You started with one file. Now it’s too large and needs to be split.

Existing Project Example:

main/
    settings.py

settings.py used everywhere. Maybe dozens of imports depend on it.

Migration Strategy (Safe Method)

Never "big bang" rewrite settings in one move. Use staged migration

Step 1: Create New Folder

main/settings/

Add:

__init__.py
base.py
dev.py
prod.py

Step 2: Copy Existing settings.py to base.py

Do copy first, not move or delete.

Now both exist temporarily:

python

1
2
main/settings.py
main/settings/base.py

Step 3: Create dev.py

python

1
2
3
from .base import *

DEBUG = True

Step 4: Create prod.py

text

1
2
3
from .base import *

DEBUG = False

Step 5: Update Startup Files One by One

manage.py

text

1
main.settings.dev

wsgi.py

text

1
main.settings.prod

asgi.py

bash

1
main.settings.dev

Step 6: Run Checks

python

1
2
3
python manage.py check
python manage.py runserver
python manage.py migrate

Step 7: Fix Old Direct Imports

Fixing old direct imports is the biggest challenge, since these can be scattered across the project

Search project for:

python

1
from main.settings import

Replace with:

python

1
from django.conf import settings

Then use: settings.MY_VALUE

Example:

python

1
2
3
4
5
6
7
8
# Old:
from main.settings import URL

# New:
from django.conf import settings


settings.URL

Step 8: Remove Old settings.py

Once stable and everything works as before:

delete main/settings.py

Most Common Problems During Refactor

1. Wrong Module Name

Typo:

python

1
main.setting.dev

Correct:

text

1
main.settings.dev

2. Missing init.py

settings need:

python

1
main/settings/__init__.py

3. Absolute Imports in Child Files

Wrong:

python

1
from base import *

Correct:

text

1
from .base import *

4. Legacy Imports from Old Settings

Breaks startup. Use django.conf.settings

5. Production Still Uses Old Settings

Check: - Gunicorn command - Docker env vars - systemd - Heroku config - Railway/Render variables

base.py

Shared configuration: - installed apps - middleware - templates - auth - timezone - common DB defaults

dev.py

Developer environment: - DEBUG=True - sqlite or local postgres - debug toolbar - permissive hosts

prod.py

Production: - DEBUG=False - strict ALLOWED_HOSTS - secure cookies - SSL redirects - Redis - logging - CDN/static storage

test.py

Testing: - fast password hasher - in-memory email backend - temporary DB tweaks

If project is new: Split immediately to avoid future complexity, if project is expected to grow large over time.

If project exists and has: - multiple environments - multiple engineers - ~300 line settings file - deployment complexity

Split as soon as possible.

If you wait until settings.py is 1200 lines, refactoring hurts. If you split at 100 lines, it takes 15 minutes.

Join the Newsletter

Practical insights on Django, backend systems, deployment, architecture, and real-world development — delivered without noise.

Get updates when new guides, learning paths, cheat sheets, and field notes are published.

No spam. Unsubscribe anytime.



There is no third-party involved so don't worry - we won't share your details with anyone.