Fix Django models.W042 Auto-Created Primary Key Warning
Fix the Django models.W042 warning about auto-created primary keys: choose between AutoField and BigAutoField for DEFAULT_AUTO_FIELD, avoid surprise migrations on large tables, handle third-party apps, and prepare for the BigAutoField default in Django 6.0.
Problem statement
Every management command prints a block of warnings, one per model:
WARNINGS:
orders.Order: (models.W042) Auto-created primary key used when not defining a
primary key type, by default 'django.db.models.AutoField'.
HINT: Configure the DEFAULT_AUTO_FIELD setting or the
OrdersConfig.default_auto_field attribute to point to a subclass of AutoField,
e.g. 'django.db.models.BigAutoField'.
Django 3.2 introduced DEFAULT_AUTO_FIELD so projects could choose the type of implicit id columns. Projects created before 3.2 never set it, so Django warns that it is falling back to the 32-bit AutoField. The warning is harmless at runtime, but it clutters CI output, hides real warnings, and the choice you make to silence it decides whether your next makemigrations rewrites every table.
- For an existing project, set
DEFAULT_AUTO_FIELD = "django.db.models.AutoField". This silences the warning and creates no migrations. - For a new project, use
"django.db.models.BigAutoField"from the start. - To move existing tables to 64-bit ids, do it deliberately per app; it rewrites large tables. See Migrate a Django Integer Primary Key to BigInt.
- If warnings name a third-party app, upgrade that package; recent versions set
default_auto_fieldin theirAppConfig. - Before upgrading to Django 6.0, pin the setting explicitly, because 6.0 changed the default to
BigAutoField.
Step-by-step solution
1. Decide what the existing tables are
Check what type your id columns already have. On PostgreSQL:
SELECT table_name, data_type
FROM information_schema.columns
WHERE column_name = 'id' AND table_schema = 'public'
ORDER BY table_name;
integer means AutoField; bigint means BigAutoField. Projects started on Django 3.2 or later with the default startproject template already have BigAutoField in settings and bigint columns. Older projects have integer.
2. Silence the warning without migrations
Match the setting to what is already in the database:
# settings/base.py
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
Run python manage.py makemigrations --check --dry-run. It should report "No changes detected". If it lists AlterField operations on id, the value does not match the existing migrations; set it back and look at which apps differ.
3. Use BigAutoField for new apps only
You can keep the project default at AutoField and opt new apps into 64-bit keys through their AppConfig:
# billing/apps.py
from django.apps import AppConfig
class BillingConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "billing"
The app's first migration then creates bigint ids. Foreign keys pointing at these models are bigint too, which Django handles automatically.
4. Deal with third-party apps
If the warnings name models from installed packages, such as taggit.Tag or an older django-celery-results, you cannot edit their AppConfig. Upgrade the package first; most maintained apps set default_auto_field since Django 3.2. For abandoned apps, override the config in your own project:
# config/apps.py
from taggit.apps import TaggitAppConfig
class TaggitConfig(TaggitAppConfig):
default_auto_field = "django.db.models.AutoField"
Then list "config.apps.TaggitConfig" in INSTALLED_APPS instead of "taggit". Never run makemigrations for a third-party app; migrations generated into site-packages disappear on the next install.
5. Prepare for Django 6.0
Django 6.0 changed the default value of DEFAULT_AUTO_FIELD to BigAutoField. A project that relied on the implicit AutoField and upgrades without setting the value will see makemigrations propose altering every id and every foreign key column. Set the value explicitly before the upgrade, as in step 2, and the upgrade produces no schema changes. The Django Upgrade Checklist covers the rest of the upgrade.
Explanation
An AutoField maps to a 32-bit integer, which overflows at 2,147,483,647 rows. Most tables never get close, but event logs, audit trails, and notification tables can, and running out of ids stops all inserts. BigAutoField maps to a 64-bit integer and removes the problem for practical purposes, at the cost of 4 extra bytes per row and per foreign key.
Changing an existing column from integer to bigint on PostgreSQL rewrites the table and every table with a foreign key to it, holding an ACCESS EXCLUSIVE lock for the duration. On a table with tens of millions of rows that is minutes of downtime. That is why silencing the warning should match the current schema, and conversion should be planned separately.
Edge cases / notes
- Many-to-many tables. Implicit through tables follow the same setting, so they get
AlterFieldoperations too when the default changes. - Swappable user model. Changing the type of
auth.Userids affects every table that references users. Treat it as a planned migration. - MySQL.
ALTER TABLE ... MODIFY id BIGINTalso rebuilds the table. Use an online schema tool for large tables. - SQLite. Both types are stored as 64-bit integers, so the change is cosmetic, but migrations are still generated.
Next steps
- Plan a conversion with Migrate a Django Integer Primary Key to BigInt.
- Review risky operations before deploy with the Django Migration Review Checklist.
- Read Run Django Schema Changes on Large Tables for lock-safe patterns.
FAQ
Is W042 dangerous?
No. It is a warning that Django is using a default. The only real risk is a high-volume table reaching the 32-bit limit years later.
Why did makemigrations create migrations for every app?
The setting you chose differs from the type in existing migrations. Set it to match the database, usually AutoField for old projects, and the migrations disappear.
Can I silence the warning with SILENCED_SYSTEM_CHECKS?
You can add "models.W042", but that hides the decision rather than making it. Setting DEFAULT_AUTO_FIELD explicitly is clearer and survives the Django 6.0 default change.
Should I convert everything to BigAutoField?
Not by default. Convert tables that grow quickly or that already hold hundreds of millions of rows, one at a time, during a planned change.