What's the best way to extend the User model in Django?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
The best way to extend Django's user model depends mostly on when you are making the decision. For a new project, the usual best practice is to create a custom user model from the start, typically by subclassing AbstractUser. For an existing project that already depends on the built-in user table, a one-to-one profile model is often safer.
Best Default for New Projects: Subclass AbstractUser
If you are starting a new Django project, create your own user model early and point AUTH_USER_MODEL at it. This gives you room to add fields later without being trapped by the default auth.User.
Then in settings.py:
This keeps the familiar Django username, password, groups, and permissions behavior while giving you a place for project-specific fields and methods.
Use AbstractBaseUser Only When You Truly Need It
Some projects need a completely custom authentication shape, such as email-only login with no username field or unusual admin behavior. In those cases, subclassing AbstractBaseUser gives full control, but it also requires more work because you must define fields, manager methods, and admin integration yourself.
That makes AbstractBaseUser powerful but not the best default. If all you need is "the standard user plus a few extra fields," AbstractUser is usually the right tradeoff.
Existing Project: Consider a Profile Model
If the project already uses the built-in user model in production, swapping to a custom user model late can be painful because of migrations, foreign keys, and third-party app assumptions. In that case, a one-to-one profile model is often the safer extension strategy.
This does introduce an extra join, but it avoids a risky mid-project user model replacement.
Always Reference the User Model Indirectly
Whether you use a custom model or the built-in one, do not hardcode auth.User in app code. Use settings.AUTH_USER_MODEL for model relationships and get_user_model() when you need the class at runtime.
This keeps reusable apps and internal code compatible with whichever user model the project uses.
Think About Authentication Requirements Early
The hardest part of user customization is not writing the model. It is deciding what the application means by "user." Questions worth answering early include:
- Is email the real unique login field.
- Do you need extra profile fields immediately.
- Will third-party authentication providers be involved.
- Do staff and customer accounts need different behavior.
Those decisions affect whether AbstractUser is enough or whether a deeper redesign is needed. Making them early is much cheaper than retrofitting later.
Avoid Mid-Project User Model Swaps
Changing AUTH_USER_MODEL after initial migrations is one of the more painful refactors in Django. It affects foreign keys, migration dependencies, admin setup, and sometimes third-party packages. If the project is still young, it can be worth doing. If the project is mature, a profile model or targeted custom tables are often safer.
Common Pitfalls
- Starting a new project with the default user model and planning to change it later.
- Choosing
AbstractBaseUserwhenAbstractUserwould have been simpler. - Referencing
auth.Userdirectly instead ofAUTH_USER_MODELorget_user_model(). - Swapping the user model mid-project without understanding the migration cost.
- Putting every unrelated domain field directly on the user model without clear need.
Summary
- For new projects, a custom user model based on
AbstractUseris usually the best default. - Use
AbstractBaseUseronly when you need full authentication customization. - For existing projects, a one-to-one profile model is often the safer extension path.
- Always reference the user model indirectly with
AUTH_USER_MODELorget_user_model(). - Decide user requirements early because changing the model later is expensive.

