Organizing Django Apps Inside an apps/ Directory
Instead of having all your apps clutter up your project's directory, organizing them in a dedicated 'apps/' directory makes the project more structured.
As soon as Django projects grow past just one or two apps, many teams move all first-party apps into a dedicated directory: apps/
Instead of:
project/
blog/
users/
billing/
orders/
they use:
project/
apps/
blog/
users/
billing/
orders/
This is a common enterprise Django pattern because it creates a clear separation between:
- project configuration
- business applications
- shared infrastructure
- deployment/runtime files
This article explains:
- How to start a project with an apps/ directory
- How to refactor an existing Django project safely
Want to read more on Django apps in detail? Django Apps: Complete Guide
Why Use an apps/ Directory?
Default Django structure works well for small projects.
But as complexity grows, the root folder often becomes crowded:
project/
blog/
users/
orders/
billing/
settings.py
urls.py
utils.py
celery.py
scripts/
This mixes business domains with framework configuration.
Using an apps/ package gives structure:
project/
config/
apps/
common/
Way easier to navigate and maintain.
What Belongs in apps/
Only first-party Django apps that represent business capabilities.
Good examples:
- apps/users
- apps/blog
- apps/orders
- apps/billing
- apps/projects
- apps/support
Bad examples:
- apps/utils
- apps/helpers
- apps/common_functions
- apps/random_stuff
Those belong in shared/internal libraries, not Django apps.
Recommended Full Project Layout
project/ │ ├── manage.py │ ├── config/ │ ├── settings/ │ ├── urls.py │ ├── asgi.py │ └── wsgi.py │ ├── apps/ │ ├── users/ │ ├── blog/ │ ├── billing/ │ ├── orders/ │ └── projects/ │ ├── common/ ├── requirements/ └── scripts/
We have a full article describing Django Enterprise Structure -> Django Enterprise-scale projects
Approach 1 — Using apps/ at Project Start
This is the easiest and cleanest moment to do it.
Step 1: Create Django Project
⧉
1 | |
Now you have:
config/
settings.py
urls.py
Step 2: Create apps/
apps/
__init__.py
Important: apps/init.py makes it a Python package.
Step 3: Create Apps Inside It
⧉
1 2 3 | |
Step 4: Register Apps
In settings:
⧉
1 2 3 4 5 6 7 8 | |
Step 5: Configure Each apps.py
Example for apps/blog/apps.py:
⧉
1 2 3 4 5 6 | |
Alter the name by prepending the apps parent directory name, 'apps' in this example. This gives django the relative path to your app.
That's why we define a label as well. This way we can still reference the app by just the name without having to carry the prefix inside every reference.
Example:
⧉
1 | |
This preserves clean references:
⧉
1 2 3 4 5 | |
Highly recommended.
We have a full guide on apps.py -> Django apps.py
Why Starting This Way Is Best
- No broken imports.
- No migration surprises.
- No refactor cost later.
Approach 2 — Refactoring an Existing Project into apps/
This is very common.
You have:
project/
blog/
users/
billing/
Now you want:
project/
apps/
blog/
users/
billing/
This can be done safely.
Important Warnings:
- Do not casually rename apps without understanding migrations.
- Django stores app labels in migrations and database metadata.
- Move carefully.
Step 1: Create apps/
apps/
__init__.py
Step 2: Move Folders
From:
blog/ users/ billing/
To:
apps/
blog/
users/
billing/
Step 3: Update apps.py
Before:
⧉
1 2 | |
After:
⧉
1 2 3 | |
When refactoring an existing project we have to define a label or if one existed keep it the same:
this helps preserve:
- migration references
- DB table names
- ForeignKey strings
- admin internals
Without it, Django may think it is a new app!
Step 4: Update INSTALLED_APPS inside settings
Rename the apps
From: "blog"
To: "apps.blog"
Step 5: Update Python Imports
Old:
⧉
1 2 | |
New:
⧉
1 2 | |
This can be the most tedious step since imports can be scattered. Search across the project and change the import paths.
Step 6: Test Startup
⧉
1 2 | |
Especially missed Python imports will show up here.
Step 7: Test Migrations
⧉
1 2 | |
If labels were preserved correctly, usually no issues.
Migration Safety Notes
If your original app was:
⧉
1 | |
and you change to:
⧉
1 2 | |
Django usually keeps migration identity stable.
So keeping label definition is the safest pattern.
Common Problems During Refactor
1. Forgot init.py
Rquired: apps/init.py
2. Wrong name
Wrong:
⧉
1 | |
after move.
Correct:
⧉
1 | |
3. Missing label
Can break migration identity.
Use:
⧉
1 | |
4. Old Imports Still Exist
⧉
1 | |
5. Circular Imports Surface
Refactors often expose hidden bad imports.
Use:
⧉
1 | |
or service-layer imports.
Should Third-Party Apps Go Inside apps/?
Short answer -> No.
Only your own apps go in /apps.
What About Shared Utilities?
Use another package:
- common/
- core/
- shared/
- lib/
Example:
- common/email.py
- common/storage.py
- common/permissions.py
Not Django apps.
Complete Django /apps Refactor Checklist
Every Place Old App Paths Can Break After Moving Apps into an apps/ Directory
When you move apps from:
blog/ users/ billing/
to:
apps/
blog/
users/
billing/
you must update every dotted Python path that references the old location.
Example:
⧉
1 2 3 4 | |
must become:
⧉
1 2 3 4 | |
Missing even one causes runtime errors.
Priority Order
Check your refactoring steps in this order:
- apps.py
- INSTALLED_APPS
- imports
- middleware
- urls
- Channels / ASGI
- signals
- Celery
- template tags
- management commands
- tests
- migrations
- admin
- external deploy config
Red Flags After Refactor
If you see:
No module named 'blog'
or:
Cannot import 'blog'
or:
LookupError: No installed app with label ...
You missed one of the locations above.
Validation Commands after Refactor or possible fixes:
Run:
⧉
1 2 3 4 | |
Then test:
- admin
- websocket pages
- celery tasks
- custom commands
- templates
- login/logout
If your Django project has 3+ internal apps or 2+ developers, use an apps/ directory early.
It becomes increasingly valuable over time.
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.