How I structure a Django project for production from day one
One of the things I have changed over the years is how much structure I put into a Django project before building the first real feature.
Django’s default project structure is a good starting point, and for prototypes or smaller applications I am quite happy to keep things simple.
The problems tend to appear later.
A single settings.py grows environment-specific conditionals. The default user model becomes difficult to replace. Business logic starts appearing in views. Shared code gradually accumulates in utils.py. Deployment configuration lives partly in the repository and partly in someone’s memory.
None of these are particularly difficult problems at the beginning of a project.
They become much more expensive once the application has production data, integrations and multiple developers working on it.
I now make a small number of structural decisions early:
- Split settings by environment
- Create a custom user model before the first migration
- Organise Django apps around business responsibilities
- Keep the core app deliberately small
- Give business logic a clear home outside the HTTP layer
- Treat APIs as another interface to the same application logic
- Keep infrastructure such as storage and email configurable
- Make testing and deployment part of the project from the beginning
The important distinction for me is that this does not mean building everything on day one.
I do not need Redis, Celery, Sentry or cloud storage running locally before I have written a feature. I just want the project to have an obvious place for those concerns when they arrive.
That is the balance I try to strike between keeping Django simple and avoiding completely predictable restructuring later.
I have written up the full project structure I use, including settings, apps, services, APIs, background tasks, infrastructure, testing and deployment:
https://www.digitaledgeconsulting.co.uk/blog/how-i-structure-a-django-project-for-production
As with my previous post about service layers and thin views, this is not intended as the correct way to structure every Django project.
It is simply the structure I have arrived at after building and maintaining larger Django applications in production.
I would be interested to hear which decisions other people make at the start of a production Django project, and which ones you deliberately leave until later.