App loading order
standardintermediateDjango runs each of the three startup stages — import configs, import models, call ready() — as a full pass across every app in INSTALLED_APPS order, not app-by-app. Every app finishes stage 1 before any app starts stage 2.
Think of it as
Think of three separate roll calls, not three relay racers. Stage 1 calls every app's name in INSTALLED_APPS order and imports its config; only once every app has answered does stage 2 begin, calling the roll again to import every app's models; only then does stage 3 call ready() on each, in the same order. An app late in the list still has its config imported before an earlier app's models are — because that's stage 1 finishing everywhere before stage 2 starts anywhere.
What we're doing: Reference another app's model safely regardless of INSTALLED_APPS order, by using a string reference instead of a direct import.
- 5
- "orders.Order" is a string — Django resolves it lazily, once the whole registry has finished stage 2, so it works no matter which app is listed first in INSTALLED_APPS.
Why this works: A string reference defers resolution until the full registry is populated, so it never depends on billing's models.py happening to import after orders' models.py — the two apps' relative position in INSTALLED_APPS stops mattering for this one relationship.
Importing another app's model class directly inside models.py
Wrong
Better
What you see: ImportError or circular-import failure that depends on whether "billing" or "orders" comes first in INSTALLED_APPS — works today, breaks after someone reorders the list.
Why: A direct import forces Python's own import machinery to resolve orders.models while billing.models is still mid-import (stage 2) — if orders also imports something from billing, the two imports can deadlock each other. A string reference avoids the problem entirely by not importing the other app's module at all.
- Stage 1 — import every apps.py
- leads to Stage 2 (all apps done)
- Stage 2 — import every models.py
- leads to Stage 3 (all apps done)
- Stage 3 — call every ready()
What is safe to do in each stage
Together
Remember: Each of the three startup stages runs across every app, in INSTALLED_APPS order, before the next stage begins anywhere — not stage 1-2-3 per app.
See also: app registry · import time side effects · app apps py

