Fix Django LookupError: No Installed App With Label

Fix the Django LookupError no installed app with label in production, migrations, and Celery: add the app to INSTALLED_APPS, use the right app label, load the correct settings module, and avoid model imports before Django is ready.

Problem statement

A command or request fails with:

LookupError: No installed app with label 'billing'.

Sometimes with more context:

File ".../django/apps/registry.py", line 165, in get_app_config
    raise LookupError(message)
LookupError: No installed app with label 'admin'.

Something asked Django's app registry for an app by its label, through apps.get_model("billing", "Invoice"), a migration dependency, a ForeignKey("billing.Invoice") string, or a management command such as migrate billing, and the registry has no app with that label. Either the app is not in INSTALLED_APPS for the settings this process loaded, or the label is different from what you think.

Why the lookup failsCode asksget_app_config(label)Registry builtfrom INSTALLED_APPSLabel missingwrong settings?LookupErrorapp not foundThe registry only contains apps listed in the settings module this process loaded.
  1. Print the labels Django knows: python manage.py shell -c "from django.apps import apps; print(sorted(a.label for a in apps.get_app_configs()))".
  2. If the app is missing, add it to INSTALLED_APPS in the settings used by this environment.
  3. Check DJANGO_SETTINGS_MODULE; production may load a settings file with a shorter app list.
  4. Use the app label (the last part of the module name, or AppConfig.label), not the full path.
  5. For 'admin' errors, a third-party package or URL import needs django.contrib.admin installed.

Step-by-step solution

1. List what the registry contains

Run the command in the failing context, for example inside the production container:

python manage.py shell -c "from django.apps import apps; print(sorted(a.label for a in apps.get_app_configs()))"
python manage.py diffsettings | grep -E "SETTINGS_MODULE|INSTALLED_APPS"

If billing is absent, the settings module did not include it. If something similar, such as billing_app, is present, the label differs.

2. Check which settings module is loaded

Split settings are the most common cause. INSTALLED_APPS in production.py may be a copy that drifted from base.py, or a deploy may set DJANGO_SETTINGS_MODULE to an old module:

# settings/production.py, risky
INSTALLED_APPS = ["django.contrib.admin", ..., "orders"]   # forgot billing

# better: extend instead of redefine
from .base import *  # noqa
INSTALLED_APPS += ["storages"]

Define the full list once in base.py and only append in environment files.

find the mismatchWhat you findCause and fixapp absent from the listnot in INSTALLED_APPShere; add it to basesimilar label presentAppConfig.labeldiffers; use that labelworks locally, not in prodother settings module;check the env varlabel is admin or authpackage expects contribapp; install itThe registry is built only from the settings this process loadeddjango-deployment.com
Print the registry in the failing environment before changing code.

3. Use the correct label

The label defaults to the last component of the app module. For apps.billing, the label is billing, not apps.billing. A custom AppConfig can override it:

class BillingConfig(AppConfig):
    name = "apps.billing"
    label = "invoicing"

Now model references and migration dependencies must use invoicing. Changing a label on an existing app also renames its tables (invoicing_invoice) and its migration history, so never change it casually.

4. Remove references to apps you uninstalled

If you removed an app from INSTALLED_APPS, old migrations in other apps may still depend on it, or call apps.get_model("oldapp", ...) in a RunPython. Leave the app installed until its references are squashed away, or edit the old migrations to drop the dependency when nothing else needs it. Data migrations should look models up defensively when the app is optional.

5. Do not import models too early

Importing models at module level in a file loaded during settings, such as a custom storage class or a logging filter referenced from settings, runs before the registry is ready. That usually raises AppRegistryNotReady, but code that calls apps.get_app_config() early can raise LookupError instead. Move imports inside functions. See Fix Django AppRegistryNotReady in Celery and Scripts.

where INSTALLED_APPS comes fromDJANGO_SETTINGS_MODULEpicks the fileproduction.pyappends extra appsbase.pydefines the full listApp registrybuilt at django.setup()Define apps once and append per environmentdjango-deployment.com
Redefining INSTALLED_APPS in an environment file is the classic source of drift.

Explanation

Django's AppRegistry maps labels to AppConfig objects when django.setup() runs. Every string reference to a model, like "billing.Invoice", is resolved through that map. The registry knows nothing about apps that exist on disk but are not listed, which is why a perfectly importable package still produces LookupError. Because the list comes from settings, the error is almost always about which settings module a process uses, not about the code itself.

Edge cases / notes

  • Celery workers. A worker started without DJANGO_SETTINGS_MODULE may fall back to a default in celery.py that points at development settings.
  • Tests. Test settings that trim INSTALLED_APPS for speed can break migrations that depend on removed apps.
  • Duplicate labels. Two apps with the same label raise ImproperlyConfigured: Application labels aren't unique instead.

Next steps

FAQ

What is an app label?

A short unique name for an app, by default the last part of its Python path. It is used in model references, migration names, and table names.

Why does migrate say No installed app with label?

migrate billing uses the label. If the app is not installed in the active settings or has another label, the command cannot find it.

Can I rename an app label?

Only with care. Table names and migration records include the label, so renaming needs migrations that rename tables and update django_migrations.

Why does it mention admin when I do not use it?

A package or your URL configuration imports admin features, which require django.contrib.admin in INSTALLED_APPS.

Keep going