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.
Starting Clean vs Refactoring an Existing Project 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: 1. How to start a project with an apps/ directory 2. How to refactor an existing Django project safely
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.
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
Part 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: Fix Each apps.py
Example:
⧉
1 2 3 4 5 6 | |
Why Add label
Use:
⧉
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.
Part 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 Warning: 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/ apps/users/ apps/billing/
Step 3: Update apps.py
Before:
⧉
1 2 | |
After:
⧉
1 2 3 | |
Why Keep Same Label?
This is critical.
If old app label was 'blog'
keeping:
⧉
1 | |
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 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.
Step 6: Test Startup
⧉
1 2 | |
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. This 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.
Example Refactor Result:
apps/
blog/
apps.py
models.py
views.py
migrations/
users/
billing/
Should Third-Party Apps Go Inside apps/?
Short answer -> No.
Keep in INSTALLED_APPS normally: "django.contrib.admin" "rest_framework" "channels"
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/ apps/users/ apps/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 in this order: 1. apps.py 2. INSTALLED_APPS 3. imports 4. middleware 5. urls 6. Channels / ASGI 7. signals 8. Celery 9. template tags 10. management commands 11. tests 12. migrations 13. admin 14. 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.