Static Files in Production

This page covers how to serve next.dj static assets in production. It covers the build step, the staticfiles finder integration, content hashing, and the CDN integration.

Overview

next.dj contributes NextStaticFilesFinder (dotted path next.static.NextStaticFilesFinder) that exposes every co-located asset to Django’s standard staticfiles pipeline. NextFrameworkConfig.ready appends it to STATICFILES_FINDERS automatically, so no manual configuration is required. Production deployments use collectstatic exactly as they would for any other Django project.

Verify the Finder

To confirm the finder is active, run the command below with a path that matches a component the project actually ships.

shell
uv run python manage.py findstatic next/components/note_card.css

If the file is not found, check that next is in INSTALLED_APPS and that the component named in the path exists.

Build Step

Run collectstatic during the deployment build.

shell
uv run python manage.py collectstatic --noinput

Django copies every co-located file into STATIC_ROOT. The default stems are component, layout, and template, the default kinds are css, js, and module (extensions .css, .js, .mjs). Files registered under custom stems and custom kinds are copied through the same finder, so an extension added through default_kinds.register ships with the rest. Project static/ directories and any directory listed in STATICFILES_DIRS are copied as well.

Hashed URLs

The default StaticFilesBackend resolves every asset URL through Django staticfiles. Pair it with Django’s ManifestStaticFilesStorage so each URL carries a content hash that changes only when the file content changes, which makes long lived browser cache lifetimes safe.

rendered output example
<link rel="stylesheet" href="/static/next/components/note_card.a1b2c3d4.css">

Configure the web server or the CDN to honour long Cache-Control headers on the static origin.

Manifest Storage

For projects that use Django ManifestStaticFilesStorage the framework cooperates without extra configuration. collectstatic writes the manifest, the framework reads it at runtime, and the rendered HTML uses the manifested filenames.

config/settings.py
STORAGES = {
    "staticfiles": {
        "BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage",
    },
}

CDN

Use a CDN aware backend to point asset URLs at a CDN host.

notes/backends.py
from next.static import StaticFilesBackend

CDN = "https://cdn.example.com"

class CdnBackend(StaticFilesBackend):
    def render_link_tag(self, url, *, request=None) -> str:
        return f'<link rel="stylesheet" href="{CDN}{url}">'

    def render_script_tag(self, url, *, request=None) -> str:
        return f'<script src="{CDN}{url}" defer></script>'

    def render_module_tag(self, url, *, request=None) -> str:
        return f'<script type="module" src="{CDN}{url}"></script>'

Register the backend in DEFAULT_STATIC_BACKENDS and configure the CDN to pull from the static origin.

Pre Compressed Files

For Brotli or gzip support, generate the compressed files during the build.

shell
uv run python manage.py collectstatic --noinput
find ./staticfiles -type f \( -name "*.css" -o -name "*.js" \) -exec brotli -f -k {} \;

The ./staticfiles path stands for the directory configured as STATIC_ROOT. Configure the web server or CDN to serve the pre compressed copies based on the Accept-Encoding header.

Service Workers

A service worker that caches assets must invalidate when the content hash changes. Read the rendered URL and key the cache on the full path, which already carries the content hash in the filename.

System Checks

Run uv run python manage.py check --deploy before shipping. The Django deployment checks cover STATIC_ROOT and STATIC_URL, and the framework static checks validate that the static backend chain is well formed.

See Also

See also

Static Assets for the topic subtree. Customise Rendered Static Tags for the backend recipe.