The default layout Django hands you is a starting point. Most teams treat it as a destination.
Every Django project begins the same way. You type django-admin startproject myproject and in three seconds you have a tidy directory: settings.py, urls.py, wsgi.py. It is clean. It is simple. And for a project that will never grow beyond a prototype, it is perfectly fine.
The problem is that most projects do grow. And when they do, the default layout starts to work against you.
Project structure is not a style preference. It is a load-bearing architectural decision that determines how easily your codebase can be understood, tested, and extended by people who were not there when it was written.
The Three Ways the Default Layout Breaks Down
1. The God Settings File
The default settings.py is a single file. By the time you have added database configuration, static files, installed apps, logging, cache backends, email settings, third-party integrations, and a few environment-specific overrides, that file is six hundred lines long.
More dangerous than the length is the assumption baked in: that your local development environment and your production environment want the same configuration. They do not. The usual solution is to litter settings with conditionals:
# BAD: conditional spaghetti in settings.py
DEBUG = True
if os.environ.get('ENVIRONMENT') == 'production':
DEBUG = False
DATABASES = {'default': {'ENGINE': 'django.db.backends.postgresql', ...}}
else:
DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3', ...}}
This works. Until a developer forgets to set the environment variable and deploys debug mode to production. Until you need a staging environment. Until the nesting is three levels deep and nobody is sure which branch is actually active.
2. The Flat App Structure
startapp creates apps in the root directory alongside manage.py. For one app this is fine. For ten, it is a flat list that communicates nothing about your architecture. The deeper problem is apps that are either too large (one giant core app with every model in the project) or too small (one app per database table, with a web of circular imports connecting them).
3. The Missing Business Logic Layer
The default structure gives you models and views. It gives you no guidance on where business logic lives. The result in most codebases: it lives everywhere. Some in models, some in views, some in serializers, some in a file called helpers.py that grows to contain everything that did not fit anywhere else.
What a Professional Layout Looks Like
Here is the structure that fixes all three problems:
myproject/
.env # Environment variables — never commit
.env.example # Template — always commit
requirements/
base.txt # Shared dependencies
local.txt # Development only
production.txt # Production only
Makefile # Common dev commands
manage.py
config/ # Project configuration (renamed from myproject/)
settings/
base.py # Shared settings
local.py # Development overrides
production.py # Production overrides
test.py # Test-specific settings
urls.py
wsgi.py
asgi.py
apps/ # All Django applications
users/
services.py # Business logic
models.py
views.py
tests/
orders/
...
Three Changes That Matter Most
1. Rename the inner directory to config/
The inner directory named after your project (myproject/myproject/) tells a new developer nothing. Renaming it config/ communicates its purpose immediately. To do this at project creation time: django-admin startproject config . — note the dot.
2. Group all apps under apps/
Add apps/ to your Python path in settings and your apps can be referenced as 'users' rather than 'apps.users'. Your project root stays clean. New developers can orient themselves in seconds.
3. Split requirements by environment
Three files, not one. local.txt starts with -r base.txt and adds django-debug-toolbar, factory-boy, pytest. production.txt adds gunicorn and sentry-sdk. Your production environment never installs your development tools.
✓ The one rule worth memorizing
The config/ directory contains project-level configuration only. The apps/ directory contains all domain code. Nothing else belongs at the project root.
The Payoff
These are not cosmetic changes. They are the decisions that determine whether, six months from now, a new developer can navigate your project in an afternoon or spend a week getting oriented. Structure is the first thing everyone inherits and the last thing anyone wants to refactor.
If you are starting a new project this week, spend the extra ten minutes getting this right. If you are inheriting an existing project, understanding why it is structured the way it is will tell you most of what you need to know about the decisions made before you arrived.
Top comments (0)