Skip to main content
Premium

Configuration

Configure the upload provider and settings in your settings.py:

All upload settings live under the single HABARICO_UPLOADS namespace (mirrors HABARICO_PREFERENCES and ADMIN_REST_FRAMEWORK):

HABARICO_UPLOADS = {
# Ordered list of providers to enable: any of "s3", "tus". Default [] (chunked upload
# disabled, base64 only - fully backward compatible). For each field the first entry whose
# provider supports that field's storage wins, so earlier entries have priority.
# Unknown names raise ImproperlyConfigured at startup.
"ENABLED_PROVIDERS": ["s3", "tus"],

# File-size threshold in bytes at/above which chunked upload is used; default 5 MB
"CHUNK_THRESHOLD": 5_242_880,

# Size of a single chunk/part in bytes; default 5 MB (S3 clamps to its 5 MB minimum)
"CHUNK_SIZE": 5_242_880,

# Largest file in bytes an upload may claim; None (the default) applies no limit of your own
"MAX_UPLOAD_SIZE": None,

# Content types refused at `initiate` by default, regardless of what a field's own allowlist
# derives to. Override to change the list, or set to an empty collection to disable the floor
# project-wide. See [Content-type allowlisting](./frontend-contract.md#content-type-allowlisting).
"DANGEROUS_CONTENT_TYPES": {"text/html", "application/xhtml+xml", "image/svg+xml"},

# S3 configuration (used when "s3" is enabled); the bucket/region/endpoint/credentials come
# from the target field's django-storages S3 backend - only upload knobs live here.
"S3": {
"TMP_PREFIX": "tmp/uploads/", # Temporary files prefix (within the storage location)
"PRESIGN_EXPIRY": 3600, # Presigned URL expiry in seconds
},

# TUS configuration (used when "tus" is enabled); requires "ENDPOINT" to be available.
"TUS": {
"ENDPOINT": "https://tusd.example.com/files/", # TUS server endpoint
"TMP_PREFIX": "tmp/uploads/", # Temporary files prefix
"TMP_STORAGE": None, # Django storage alias holding the finished upload; None = default_storage
},
}
KeyDefaultWhat it does
ENABLED_PROVIDERS[]Ordered provider list; [] disables chunked upload entirely
CHUNK_THRESHOLD5_242_880File size in bytes from which the chunked path is taken
CHUNK_SIZE5_242_880Size of one chunk / multipart part
MAX_UPLOAD_SIZENoneLargest file (bytes) an upload may claim; None applies no limit of your own. See Upload size limits
DANGEROUS_CONTENT_TYPES{"text/html", "application/xhtml+xml", "image/svg+xml"}Content types refused by default; override or empty at your own risk. See Content-type allowlisting
S3["TMP_PREFIX"]"tmp/uploads/"Prefix of the temporary object inside the field's storage
S3["PRESIGN_EXPIRY"]3600Lifetime of a presigned URL, in seconds
TUS["ENDPOINT"]Nonetus server URL; without it the tus provider is unavailable
TUS["TMP_PREFIX"]"tmp/uploads/"Prefix the tus server writes under
TUS["TMP_STORAGE"]NoneDjango storage alias the finished upload is read from; None uses default_storage

Upload size limits​

The S3 provider presigns one URL per part, and the part count follows the size the client claims for a file nobody has uploaded yet. It therefore refuses outright, before anything is created in S3, any upload that would need more than providers.s3.MAX_PARTS — 10 000 parts, S3's own multipart limit. That ceiling is not configurable: an upload past it could not be completed by S3 either way.

MAX_UPLOAD_SIZE is your own policy on top of that, and it is off by default. Left None, the effective ceiling is MAX_PARTS * CHUNK_SIZE — roughly 48.8 GiB at the default chunk size. Set it when your files are known to be far smaller:

HABARICO_UPLOADS = {"MAX_UPLOAD_SIZE": 104_857_600} # 100 MiB

A field may also carry a MaxFileSizeValidator of its own (see Per-field size limits). The two do not override each other — initiate applies whichever of the two is stricter, so MAX_UPLOAD_SIZE stays the project-wide ceiling no field can raise.

Either limit raises UploadTooLarge, which initiate answers with 422 Unprocessable Entity like every other upload error — the same status the Ruby library answers with; the frontend shows the message on the file's row. The limit is a policy, not a guarantee — nothing verifies the claimed size against the bytes that actually arrive, so pair it with the lifecycle rule in S3 temporary file cleanup.

tip

The S3 and TUS blocks are merged key by key with their defaults, so setting only TUS["ENDPOINT"] keeps the default TMP_PREFIX. The top level merges the same way: every key left out of HABARICO_UPLOADS falls back to its default individually.