django-storages with multiple S3 Buckets
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Using more than one S3 bucket in a Django project is a normal requirement, not an edge case. Teams often want one bucket for static assets, another for user uploads, and sometimes a third for private documents or backups. django-storages supports that cleanly once you stop thinking in terms of one global storage backend and start defining separate storage classes.
Why Multiple Buckets Help
Different file types usually have different operational needs.
- Static files are often public and aggressively cached.
- Media uploads are usually private or at least overwrite-sensitive.
- Internal exports may need tighter IAM rules and shorter retention.
Putting all of those objects in one bucket makes permissions, lifecycle policies, and CDN behavior harder to manage. Separate buckets let you keep the rules simple.
Define Separate Storage Backends
The core pattern is to create a storage class for each bucket. That lets Django choose the right backend per use case instead of relying on one global DEFAULT_FILE_STORAGE.
This is the most readable setup because the bucket choice is encoded in Python instead of being buried in conditionals.
Wire Static Files And Uploaded Files Separately
Static files and uploaded media are configured differently in Django.
With this setup:
- '
collectstaticwrites to the static bucket,' - model
FileFieldandImageFielduploads use the media bucket.
That covers many projects without any additional complexity.
Use A Dedicated Storage On Specific Models
Sometimes only one model or field should use a different bucket. In that case, pass a storage instance directly to the field.
This is useful when most uploads go to one bucket but a specific document class needs different retention or access rules.
Django 4.2 And The STORAGES Setting
If your project uses newer Django settings conventions, you can define named storage configurations and keep the bucket details centralized.
This does not remove the need for separate storage classes. It just makes Django’s configuration style more explicit.
Credentials And Permissions Still Matter
Multiple buckets do not require multiple credential sets, but they do require IAM permissions that cover every bucket the app touches. A common deployment error is granting access to the media bucket and forgetting the static bucket.
If your app role needs both, the policy must reflect that.
The storage code can be correct while the IAM layer still blocks uploads or reads.
A Good Default Architecture
A practical split looks like this:
- one public bucket behind a CDN for static files,
- one private bucket for user uploads,
- optional additional storage classes for reports, exports, or backups.
That design keeps collectstatic, user uploads, and private file delivery from competing for the same S3 policy and lifecycle rules.
Common Pitfalls
- Using one global bucket because it seems simpler, then struggling with mixed ACL and caching needs.
- Forgetting that
STATICFILES_STORAGEandDEFAULT_FILE_STORAGEoften need different backends. - Reusing a storage class but changing only
location, when the bucket itself should differ too. - Granting IAM access to one bucket and assuming the second bucket will work automatically.
- Letting user uploads overwrite files by leaving
file_overwrite = Truewhere uniqueness matters.
Summary
- Multiple S3 buckets are best handled through separate Django storage classes.
- Static files and media uploads usually deserve different backends and policies.
- Attach a storage class globally or directly on individual model fields.
- Keep bucket access aligned with IAM permissions and deployment roles.
- A clean multi-bucket setup makes caching, privacy, and lifecycle rules much easier to manage.

