Create a Django Superuser in Production Without a Shell

Create the first Django admin user in production non-interactively: createsuperuser --noinput with DJANGO_SUPERUSER_ environment variables, one-off containers and Jobs, PaaS consoles, an idempotent management command, and securing the account afterwards.

Problem statement

The site is deployed and the admin login page works, but there is no user to log in with. python manage.py createsuperuser asks for input interactively, which is awkward or impossible in CI pipelines, Docker builds, PaaS deploy hooks, and Kubernetes. Common workarounds (hard-coding a password in a data migration, or creating users with a default password in an entrypoint) leave weak credentials in production. Django supports creating a superuser non-interactively, and there are clean patterns for doing it once.

First admin user, safelySecrets in envDJANGO_SUPERUSER_*One-off command--noinputUser createdonce, idempotentRotate + 2FAafter first loginPass credentials as one-time secrets, create the user once, then secure the account.
  1. Set DJANGO_SUPERUSER_USERNAME, DJANGO_SUPERUSER_EMAIL, and DJANGO_SUPERUSER_PASSWORD for a single run.
  2. Run python manage.py createsuperuser --noinput in a one-off container, Job, or PaaS console.
  3. Do not put this in the image build or every container start; run it once.
  4. For repeatable automation, write a small management command that creates the user only if it does not exist.
  5. Log in, change the password, and enable two-factor authentication; remove the temporary variables.

Step-by-step solution

1. Use createsuperuser --noinput

Since Django 3.0, createsuperuser --noinput reads the password from DJANGO_SUPERUSER_PASSWORD (and other required fields from DJANGO_SUPERUSER_<FIELD>):

DJANGO_SUPERUSER_USERNAME=admin \
DJANGO_SUPERUSER_EMAIL=ops@example.com \
DJANGO_SUPERUSER_PASSWORD="$(openssl rand -base64 24)" \
python manage.py createsuperuser --noinput

Generate the password, store it in your password manager, and pass it only for this command. With a custom user model that uses email as USERNAME_FIELD, set DJANGO_SUPERUSER_EMAIL and any other REQUIRED_FIELDS.

2. Run it once in your platform

  • Docker Compose: docker compose run --rm -e DJANGO_SUPERUSER_PASSWORD=... web python manage.py createsuperuser --noinput --username admin --email ops@example.com.
  • Kubernetes: a one-off Job with the password from a temporary Secret, deleted afterwards.
  • Heroku: heroku run python manage.py createsuperuser (interactive one-off dyno works).
  • Render, Railway, Fly.io: use the platform's shell or console (fly ssh console -C "python manage.py createsuperuser").
safe and unsafe ways to bootstrap an adminCredential exposureVerdict--noinput, one-off runone secret, one run✓recommendedidempotent commandsecret per environment✓good for automationdata migration with password✕password in git history✕avoidentrypoint every startsecret in every container!avoidCredentials should exist only for the moment the user is createddjango-deployment.com
Never commit an admin password, even a temporary one.

3. An idempotent command for automation

For preview environments or infrastructure-as-code flows that create environments repeatedly, a command that does nothing if the user exists is safer than createsuperuser, which fails on duplicates:

# accounts/management/commands/ensure_superuser.py
import os
from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help = "Create a superuser from environment variables if it does not exist."

    def handle(self, *args, **opts):
        User = get_user_model()
        email = os.environ["DJANGO_SUPERUSER_EMAIL"]
        if User.objects.filter(email=email).exists():
            self.stdout.write("superuser exists, nothing to do")
            return
        User.objects.create_superuser(
            username=os.environ.get("DJANGO_SUPERUSER_USERNAME", email),
            email=email,
            password=os.environ["DJANGO_SUPERUSER_PASSWORD"],
        )
        self.stdout.write(self.style.SUCCESS(f"created superuser {email}"))

Run it from the deploy pipeline with the password from the secrets store.

4. Secure the account immediately

  • Log in and change the password if it passed through any shared system.
  • Enable two-factor authentication for admin users.
  • Remove DJANGO_SUPERUSER_PASSWORD from the environment and delete temporary Secrets.
  • Create named accounts for each person instead of sharing admin, and give staff users only the permissions they need.
from no users to a secured admin1Generate a strong passwordstore in a password manager2createsuperuser --noinputone-off container or Job3Remove the temporary secretenv var, k8s Secret4Log in, enable 2FAchange password if shared5Named accounts per personleast privilegeThe bootstrap account should become one ordinary, protected accountdjango-deployment.com
Audit superusers periodically; there should be very few.

Verification check: log in to /admin/ with the new account, confirm User.objects.filter(is_superuser=True).count() is what you expect, and confirm the temporary password variable no longer exists in the running environment.

Explanation

createsuperuser prompts for values by default to avoid passwords in shell history and process lists. The --noinput mode reads required fields from command-line options and the password from an environment variable, which suits automation while keeping the password off the command line. Because the command fails if the user already exists, putting it in container startup creates errors or, worse, encourages default passwords. Running it once, or using an idempotent command with per-environment secrets, keeps bootstrap credentials short-lived.

Edge cases / notes

  • Custom user models must define create_superuser correctly and list REQUIRED_FIELDS; the env variables follow those field names.
  • SSO-only admin setups may not need local superusers; grant is_staff and permissions to SSO users instead.
  • Password validators apply in interactive mode; --noinput skips some validation, so generate strong passwords yourself.
  • Recovery. If the only superuser is locked out, run changepassword or create another superuser the same way.

Next steps

FAQ

How do I run createsuperuser without prompts?

Use createsuperuser --noinput with DJANGO_SUPERUSER_PASSWORD and the username or email fields set.

Can I create the superuser in the Dockerfile?

No. The database is not available at build time, and the password would end up in the image.

Should a data migration create the admin user?

No. It would put credentials in version control and in every environment.

What if the superuser already exists?

createsuperuser fails. Use an idempotent command that checks first.

Keep going