Storage
File uploads, storageFileId linking, and preview proxy pattern.
The storage module handles blobs across local, S3, Azure, GCS, and Aliyun providers. All binary assets flow through Conduit Storage — never base64 in database documents.
Use cases
User avatars & attachments
Upload via presigned URL, link storageFileId on profile or message
Private documents
isPublic: false with ReBAC scope checks on download
Web app file display
Preview proxy route serves bytes — browsers never see presigned URLs
Chat file messages
Upload to storage, reference file IDs in chat message payload
Capabilities
- Presigned upload/download
- S3, Azure, GCS, local
- storageFileId linking
- Preview proxy pattern
- Public & private files
- ReBAC scope on reads
- Container/folder paths
Example: Upload, link, and serve via preview proxy
Walkthrough
- App server calls POST /storage/upload with mimeType, container, folder (authenticated)
- Server PUTs bytes to the returned presigned URL (no Bearer on presigned request)
- PATCH user profile with avatarFileId: file._id on the domain document
- Browser requests /api/preview/avatar — your Next.js route fetches via Client API server-side
curl -X POST http://localhost:3000/storage/upload \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"avatar.webp","mimeType":"image/webp","size":48231,"container":"myapp-uploads","folder":"users/abc/avatars/","isPublic":false}'How it works
Presigned two-step upload
- Metadata on Conduit —
POST /storage/uploadreturns{ file: { _id }, url } - Bytes to object store —
PUT {url}withContent-Typeand raw bytes (no Authorization header) - Link domain entity — store
file._idasstorageFileId/avatarFileIdon your document
Never store presigned URLs in the database — they expire.
Preview proxy (required for browsers)
Presigned SAS/S3 URLs must not reach browsers or mobile clients. Your app server calls GET /storage/getFileUrl/:id with the user's token, fetches the presigned URL server-side, and streams bytes to the browser — the presigned URL never reaches the client. See the Next.js guide.
GET /storage/file/data/:id returns base64 and is for small server-side transforms only — not general image or video delivery to browsers.
Public vs private
isPublic: true skips auth on GET /storage/getFileUrl/:id. Private files enforce authorization when the authorization module is enabled; pass scope for ReBAC checks.
Cleanup
On entity delete, call DELETE /storage/file/{storageFileId} to remove the blob.
Configure
Provider credentials and defaultContainer via MCP ?modules=storage:
| Tool | Purpose |
|---|---|
get_config_storage | Read provider settings |
patch_config_storage | S3/Azure/GCS/local config |
Client API
| Method | Path | Auth |
|---|---|---|
| POST | /storage/upload | Required |
| PATCH | /storage/upload/:id | Required |
| GET | /storage/getFileUrl/:id | Optional (returns presigned URL in { result } — use server-side only) |
| GET | /storage/file/:id | Optional (metadata document) |
| GET | /storage/file/data/:id | Required (base64 — small server-side transforms only) |
| DELETE | /storage/file/:id | Required |
MCP
Enable ?modules=storage for provider and container configuration.