Skip to content

Storage

The core.storage layer abstracts file storage for the backend.

It provides a single place to define how files are stored and retrieved, while supporting different environments such as:

  • local development
  • production with S3-compatible object storage

This keeps the rest of the backend independent from storage backend details.


Purpose

The storage layer exists to:

  • abstract local vs remote storage
  • standardize public and private file handling
  • keep file access logic out of feature apps
  • make storage backend switching configurable

Current Storage Backends

The system currently supports two storage modes:

Local filesystem storage

Used when:

  • USE_S3 = False

S3-backed storage

Used when:

  • USE_S3 = True
  • storages is installed

Storage Types

The storage layer distinguishes between:

Public storage

Files intended to be publicly accessible.

Examples: - public media assets - images intended for direct access

Private storage

Files that should not be publicly accessible by default.

Examples: - protected uploads - restricted documents - internal attachments


Storage Resolution

Storage backend selection is performed dynamically.

The helper:

  • use_s3()

determines whether S3-backed storage should be used.

Then the factory helpers choose the correct implementation:

  • public_storage()
  • private_storage()

Public Storage

Local Public Storage

Local public storage uses a filesystem location under:

  • MEDIA_ROOT/public

Its base URL is derived from:

  • MEDIA_URL/public/

This is intended for development and simple deployments.


S3 Public Storage

S3 public storage uses:

  • location = public
  • public-read ACL
  • unsigned URLs

This is appropriate for assets that can be served directly.


Private Storage

Local Private Storage

Local private storage uses a filesystem location under:

  • MEDIA_ROOT/private

It does not expose a base URL directly.

This helps keep private files separate from public media.


S3 Private Storage

S3 private storage uses:

  • location = private
  • private ACL
  • signed URLs

This allows protected files to be served securely without making the bucket or object public.


Storage Selection Flow

flowchart TD
    A[Need storage backend] --> B{USE_S3?}
    B -->|No| C[Local Storage]
    B -->|Yes| D[S3 Storage]
    C --> E[Public or Private]
    D --> E

Main Helpers

use_s3()

Returns whether the system should use S3-backed storage.

This is controlled by Django settings.


public_storage()

Returns the configured public storage backend.

Possible result: - LocalPublicMediaStorage - S3PublicMediaStorage


private_storage()

Returns the configured private storage backend.

Possible result: - LocalPrivateMediaStorage - S3PrivateMediaStorage


Why This Abstraction Matters

Without a storage abstraction, feature apps would need to know: - where files are stored - how URLs are generated - whether storage is local or remote - whether files are public or private

The storage layer hides all of that behind a consistent API.


Relationship to Other Layers

Upload validation

Handled separately in: - uploads.md

Download access

If private downloads are introduced later, feature-specific access control should sit above the storage layer.

The storage layer only determines where files live, not who may access them.


Configuration Expectations

The storage layer depends on settings such as: - USE_S3 - MEDIA_ROOT - MEDIA_URL - installed app storages

S3-specific configuration should also be provided when S3 mode is enabled.


Design Principles

The storage layer is designed to be: - environment-aware - simple to switch - explicit about public vs private files - reusable across all apps


What Storage Should NOT Do

The storage layer should not: - perform permission checks - validate business rules - decide whether a file upload is allowed - implement feature-specific download behavior

Those concerns belong elsewhere.


Typical Usage

Feature apps should use: - public_storage() for public file fields - private_storage() for restricted file fields

This avoids hardcoding backend-specific storage classes inside feature code.


Future Extensions

The storage layer can later be extended with: - CDN-specific integration - file lifecycle policies - storage usage metrics - file expiration strategies - region-aware storage routing


Summary

The core.storage layer provides a centralized abstraction for file storage.

It ensures that: - storage backend choice is configurable - public and private files are clearly separated - feature apps remain independent from storage details