Storage

Uploads, MIME guards & a built-in CDN

The storage block gives your API file handling out of the box: multipart uploads with size and MIME validation, and a built-in CDN that serves the stored files back with caching, range requests and ETags. No S3 wiring required to get started.

Uploaded files are tracked as records (so they participate in auth and relations), and the CDN layer streams them efficiently — including partial content for video and large downloads.

Upload limits & guards#

Define what may be uploaded and how large it can be. MIME allow/block lists are your first line of defence against unwanted file types.

config.nucleus.json — storage
1{2  "storage": {3    "enabled": true,4    "basePath": "./uploads",5    "maxFileSizeBytes": 10485760,6    "allowedMimeTypes": ["image/jpeg", "image/png", "image/webp", "application/pdf"],7    "cdn": {8      "enabled": true,9      "basePath": "/cdn",10      "cacheMaxAge": 86400,11      "enableRangeRequests": true,12      "enableEtag": true,13      "corsOrigins": ["https://app.acme.com"]14    },15    "formData": { "filesField": "files", "dataField": "data", "maxFiles": 5 }16  }17}
enabledbooleanOptional

Mount the storage routes and CDN.

Defaultfalse
basePathstringOptional

Route prefix / base directory for stored files (e.g. ./uploads).

maxFileSizeBytesnumberOptional

Hard upper bound on a single upload, in bytes. e.g. 10485760 = 10 MB. Oversized uploads are rejected before they're written.

allowedMimeTypesstring[]Optional

Allow-list of accepted MIME types. When set, anything not on the list is rejected — the safest posture for user uploads.

Example: ["image/jpeg", "image/png", "image/webp"]

blockedMimeTypesstring[]Optional

Deny-list of explicitly forbidden MIME types, useful when you'd rather allow-by-default but block known-dangerous types.

CDN delivery#

Serve stored files back to clients with proper HTTP caching semantics. Range requests enable seekable media and resumable downloads; ETags enable conditional requests.

cdnobjectOptional

Built-in content-delivery configuration.

enabledbooleanOptional

Serve files over the CDN routes.

basePathstringOptional

Public path files are served under (e.g. /cdn).

cacheMaxAgenumberOptional

Cache-Control max-age in seconds sent with served files.

enableRangeRequestsbooleanOptional

Honour HTTP Range — required for video scrubbing and resumable downloads.

enableEtagbooleanOptional

Emit ETags so browsers can revalidate cheaply with 304s.

corsOriginsstring[]Optional

Origins permitted to fetch CDN assets cross-origin.

Form-data field mapping#

Multipart uploads carry the binary files in one field and a JSON metadata blob in another. These settings name those fields and cap how many files one request may carry.

recipe — upload from the browser
1// multipart upload to the storage basePath; fields match formData config2const form = new FormData();3form.append("files", file); // filesField4form.append(5  "data",6  JSON.stringify({ original_name: file.name, mime_type: file.type }),7); // dataField8 9await fetch("/api/storage", { method: "POST", body: form });10// the stored file is then served back at  <cdn.basePath>/<id>
formDataobjectOptional

Multipart request shape.

filesFieldstringOptional

The form field carrying the binary file(s) — commonly "files".

dataFieldstringOptional

The form field carrying the JSON metadata — commonly "data".

maxFilesnumberOptional

Maximum number of files accepted in a single multipart request.

Under the hood — BunFileManager#

Disk I/O goes through a single BunFileManager built on Bun's native file APIs (Bun.file / Bun.write). It's more than read/write — it's the crash-safe storage primitive the uploads and CDN sit on.

typed readstext · json · buffer · bytes · streamOptional

readFile returns the format you ask for, and getFileInfo surfaces size, MIME type, extension and timestamps — which is how the CDN sets content types and validates uploads.

streaminglarge filesOptional

writeStream / readFileStream / copyFileStream move data in chunks rather than buffering whole files in memory, so large uploads and downloads (and CDN range responses) stay flat on memory.

atomic writescrash-safeOptional

atomicWrite / atomicJsonWrite write to a temp file and swap, safeFileUpdate wraps a read-modify-write with automatic rollback, and batchAtomicOperations groups several — so a crash mid-write never leaves a half-written file.

permissionsoctal + helpersOptional

setPermissions and the makeReadable/Writable/ReadOnly helpers manage POSIX file modes, letting stored artifacts be locked down on disk.

Related sections