Static files and collectstatic¶
There are two static storages:
S3StaticStorage— serves files under their plain names. Use it when you don't need content hashing.S3ManifestStaticStorage— stores each file under a content-hashed name (style.<hash>.css), rewrites references inside CSS/JS to those names, and records astaticfiles.jsonmanifest so{% static %}resolves to the hashed name. This is what you want for cache-busting.
Both default to overwriting files in place (file_overwrite=True) and serving unsigned URLs
(querystring_auth=False) so a CDN or browser can cache them.
Configuration¶
from django.core.files.storage import FileSystemStorage
STORAGES = {
"staticfiles": {
"BACKEND": "django_capo_s3.S3ManifestStaticStorage",
"OPTIONS": {
"bucket": "my-bucket",
"location": "static",
# Keep the manifest on the local disk so web workers don't fetch it from S3 on every boot.
"manifest_storage": FileSystemStorage(location=BASE_DIR / ".static-manifest"),
},
},
}
Then, as usual:
{% static "css/app.css" %} now resolves through the manifest to the hashed object, which you can serve with
long-lived caching (Cache-Control: max-age=31536000, immutable).
Where does the manifest live?¶
By default the manifest is written to the bucket next to your assets. That means every web worker fetches it
from S3 on startup. Passing manifest_storage=FileSystemStorage(...) keeps it on local disk instead — the
manifest is baked into your build/image and read locally, which is faster and avoids an S3 round trip per
process.
Faster re-deploys¶
Unchanged assets are not re-uploaded on each deploy — skip_unchanged is on by default. See
Further optimizations.
Plain static storage¶
If you don't need hashed names (e.g. you version assets some other way):