Fix Heroku "Error While Running collectstatic" for Django

Fix the Heroku Python build error while running python manage.py collectstatic --noinput: read the hidden traceback, set STATIC_ROOT, avoid settings that need runtime config vars at build time, and fix WhiteNoise manifest errors.

Problem statement

git push heroku main builds dependencies and then fails:

remote:  !     Error while running '$ python manage.py collectstatic --noinput'.
remote:        See traceback above for details.
remote:
remote:        You may need to update application code to resolve this error.
remote:        Or, you can disable collectstatic for this application:
remote:
remote:           $ heroku config:set DISABLE_COLLECTSTATIC=1
remote:
remote:  !     Push rejected, failed to compile Python app.

The Heroku Python buildpack runs collectstatic automatically during the build. Any exception, from settings import to a missing file referenced in CSS, fails the whole push. The actual error is a few dozen lines above this message; the summary only tells you the step that failed.

Why the push is rejectedBuildpackinstalls packagesRuns collectstaticduring buildExceptionsettings or filesPush rejectedcompile failedThe real traceback sits above the summary message in the build log.
  1. Scroll up in the build output to the Python traceback; that is the real error.
  2. Set STATIC_ROOT = BASE_DIR / "staticfiles" if the error says it is not set.
  3. Avoid reading config vars that are missing at build time; use defaults for settings not needed by collectstatic.
  4. For WhiteNoise "could not be found" errors, fix the CSS or JS that references a missing file.
  5. Reproduce locally with production settings: DJANGO_SETTINGS_MODULE=... python manage.py collectstatic --noinput.

Step-by-step solution

1. Read the traceback

Run the build again and keep the full output, or open the failed build in the Heroku dashboard under Activity. Look for the last Python exception before the summary:

django.core.exceptions.ImproperlyConfigured: You're using the staticfiles app
without having set the STATIC_ROOT setting to a filesystem path.
ValueError: The file 'img/hero.webp' could not be found with
<whitenoise.storage.CompressedManifestStaticFilesStorage object at 0x7f...>.
KeyError: 'DATABASE_URL'

Each points to a different fix.

2. Set STATIC_ROOT and storage

STATIC_URL = "static/"
STATIC_ROOT = BASE_DIR / "staticfiles"
STORAGES = {
    "default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
    "staticfiles": {"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"},
}

Add whitenoise.middleware.WhiteNoiseMiddleware right after SecurityMiddleware. Without a static server, Heroku cannot serve the collected files.

match the tracebackTraceback saysCause and fixSTATIC_ROOT not setadd STATIC_ROOT =BASE_DIR / staticfilesfile could not be foundCSS or JS referencesmissing asset; fix pathKeyError for a config varnot needed forcollectstatic; use a defaultModuleNotFoundErrorpackage missing inrequirements; add itThe summary line is generic; the traceback names the causedjango-deployment.com
Reproducing locally with production settings shows the same traceback faster.

3. Handle config vars at build time

Heroku makes config vars available during the build, but add-ons attached later, review apps, and pipelines can leave some unset. Settings that read them with os.environ["X"] fail at import, before collectstatic even starts. Give non-essential settings defaults, or load them lazily:

DATABASES = {"default": dj_database_url.config(conn_max_age=60, default="sqlite:///:memory:")}
SENTRY_DSN = os.environ.get("SENTRY_DSN", "")

collectstatic does not touch the database, so a placeholder default is harmless during the build. Keep SECRET_KEY required, and set it as a config var.

4. Fix missing referenced files

CompressedManifestStaticFilesStorage rewrites url() references in CSS and import statements in JavaScript modules to hashed names. If a referenced file does not exist, it raises. Fix the path in the stylesheet, add the missing file, or, if a third-party CSS file references files you do not ship, set:

WHITENOISE_MANIFEST_STRICT = False

This only affects {% static %} lookups at runtime. For post-processing errors, the targeted fix is to correct the reference.

5. Disable automatic collectstatic only on purpose

DISABLE_COLLECTSTATIC=1 skips the step, which is useful when a frontend build creates assets in a later build step or when static files go to S3 in a release phase. Without a replacement, your site will have no CSS. Run it yourself in bin/post_compile or a release command instead.

build order on Heroku1Install Pythonfrom .python-version2Install requirementspip, Poetry, or uv3Run collectstaticunless disabled4Build the slugfiles baked in5Release phasemigrate, then startStatic files are collected into the slug before release and runtimedjango-deployment.com
Anything collectstatic needs must be installed by step two.

Explanation

The buildpack runs collectstatic so that static files are part of the slug, the compressed image Heroku boots on every dyno. Collecting at runtime would be too slow and repeated per dyno. Because the command imports your full settings and every installed app, any import-time error in the project surfaces here first. That is why "collectstatic failed" often has nothing to do with static files.

Edge cases / notes

  • Node assets. If you build CSS or JS with npm, add the Node.js buildpack before the Python one so assets exist when collectstatic runs.
  • Cached builds. Clearing the build cache (heroku builds:cache:purge) helps when an old cached package causes the error.
  • Review apps. Review apps need the same config vars; set them in app.json.

Next steps

FAQ

Can I just set DISABLE_COLLECTSTATIC=1?

It lets the push succeed, but your site then has no static files unless you collect them another way. Fix the error instead.

Are config vars available during the Heroku build?

Yes, app config vars are available to the build. Add-on variables attached after the build, or missing variables in review apps, can still be absent.

Why does collectstatic fail with a database error?

Usually a setting or app runs a query at import time. Move such code into functions or AppConfig.ready() with care.

Do I need WhiteNoise on Heroku?

Yes, or another way to serve static files such as a CDN. Heroku does not serve files from the slug automatically.

Keep going