Conduit
Conduit
Docsllms.txtHostingGitHubIntroduction

Getting Started

OverviewInstall ConduitMCP SetupYour First AppStart with AI

Learn

ArchitectureClient vs Admin APIConfiguration

Modules

OverviewAuthenticationAuthorizationDatabaseStorageCommunicationsChatRouterFunctions

Guides

Next.js IntegrationReBAC Team ScopingGitOps State Export

Deployment

Deployment OverviewDocker ComposeKubernetes and HelmLocal from SourceContainer Images

Reference

CLI ReferenceClient APIAdmin APIEnvironment VariablesMCP Tools

Resources

Migration v0.16 → v0.17Legacy DocumentationChangelogFAQGlossaryContributing

Storage

File uploads, cloud providers (S3, Azure, GCS), signed URLs, public access, folder markers, and Prometheus metrics.

The storage module handles blobs across local, AWS S3 (and S3-compatible endpoints), Azure Blob Storage, Google Cloud Storage, and Aliyun OSS. 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

Public assets

isPublic: true with CDN host mapping for cacheable delivery

Chat file messages

Upload to storage, reference file IDs in chat message payload

Capabilities

  • Presigned upload/download (60 min expiry)
  • AWS S3 & S3-compatible providers
  • Azure Blob Storage
  • Google Cloud Storage
  • Local filesystem
  • storageFileId linking
  • Preview proxy pattern
  • Public & private files and containers
  • ReBAC scope on reads
  • Container/folder hierarchy with marker files
  • CDN host mapping per container
  • Prometheus metrics (files, folders, size)

Example: Upload, link, and serve via preview proxy

Walkthrough

  1. App server calls POST /storage/upload with mimeType, container, folder (authenticated)
  2. Server PUTs bytes to the returned presigned URL (no Bearer on presigned request)
  3. PATCH user profile with avatarFileId: file._id on the domain document
  4. Browser requests /api/preview/avatar — your Next.js route fetches via Client API server-side
Request presigned upload
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

  1. Metadata on Conduit — POST /storage/upload returns { file: { _id }, url }
  2. Bytes to object store — PUT {url} with Content-Type and raw bytes (no Authorization header)
  3. Link domain entity — store file._id as storageFileId / avatarFileId on your document

Never store presigned URLs in the database — they expire after 60 minutes.

For inline base64 uploads (small files, server-side only), use POST /storage/file with a base64 data field instead.

Signed URLs

Conduit generates time-limited signed URLs for upload and download:

OperationHowExpiry
UploadPOST /storage/upload → presigned PUT/SAS/write URL60 minutes
Replace bytesPATCH /storage/upload/:id → new presigned upload URL60 minutes
Private downloadGET /storage/getFileUrl/:id → signed read URL in { result }60 minutes
Public downloadGET /storage/getFileUrl/:id → stored url (no signing)N/A

Query parameters on GET /storage/getFileUrl/:id:

ParamEffect
redirect=trueHTTP redirect to the URL instead of returning JSON
download=trueSets Content-Disposition: attachment on the signed URL

Signed URLs (S3 presigned URLs, Azure SAS tokens, GCS signed 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. 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

Access is controlled at two levels:

File level — isPublic on upload/create:

  • isPublic: true — GET /storage/getFileUrl/:id returns the stored url without auth or signing
  • isPublic: false — requires authentication (and ReBAC when authorization is enabled); download uses a signed URL

Container level — isPublic on the container document:

  • Public containers apply provider-level read policies (S3 bucket policy, Azure blob access, GCS makePublic)
  • Files in public containers cannot be marked private — Conduit rejects isPublic: false when the container is public

When authorization is enabled, pass scope on create/upload to bind ownership: File:{id} is linked to the scope resource (or the uploading user) via ReBAC.

Folder markers

Object stores have no real directories. Conduit models folders in the database (_StorageFolder) and creates marker objects in the provider:

ProviderMarker object
S3 / Azure{folderPath}.keep.txt (body: DO NOT DELETE)
GCS{folderPath}/keep.txt

Folder paths are normalized to end with / (e.g. users/abc/avatars/). On upload, findOrCreateFolders walks the path hierarchy and creates missing folders and markers. Nested paths like a/b/c/ create markers for a/, a/b/, and a/b/c/.

Specify folder on upload; omit or pass / for the container root. Containers are created automatically when allowContainerCreation is true (default).

Cloud providers

Set provider via MCP patch_config_storage. Each provider has its own credential block:

AWS S3 (provider: "aws")

Config keyPurpose
aws.regionAWS region
aws.accessKeyId / aws.secretAccessKeyIAM credentials
aws.accountIdUsed to prefix bucket names as conduit-{accountId}-{container}
aws.endpointCustom endpoint for S3-compatible providers (MinIO, DigitalOcean Spaces, etc.)
aws.usePathStylePath-style addressing for non-AWS endpoints (default: true)

When endpoint is set (non-AWS S3), accountId is auto-generated. Public containers disable the public access block and attach a bucket policy allowing s3:GetObject for all principals.

Azure Blob Storage (provider: "azure")

Config keyPurpose
azure.connectionStringStorage account connection string

Containers map to Azure blob containers. Public containers are created with blob-level public read access. Upload and download use SAS tokens.

Google Cloud Storage (provider: "google")

Config keyPurpose
google.serviceAccountKeyPathPath to service account JSON key file

Buckets map to GCS buckets. Public containers call makePublic() on the bucket; public files call makePublic() on the object. Folder markers use {path}/keep.txt. Upload and download use GCS signed URLs.

CDN mapping

Map container names to CDN hosts via cdnConfiguration:

{
  "cdnConfiguration": {
    "myapp-uploads": "cdn.example.com"
  }
}

Public files store both sourceUrl (provider URL) and url (CDN-applied). Private downloads apply CDN host replacement on signed URLs when configured.

Metrics

The storage module exports Prometheus gauges (scraped via Conduit Core):

MetricTypeDescription
containers_totalGaugeNumber of containers
folders_totalGaugeNumber of folders (marker objects created)
files_totalGaugeNumber of file documents
storage_size_bytes_totalGaugeCumulative size of all files in bytes

Gauges are updated on create and delete. File size changes adjust storage_size_bytes_total by the delta.

Cleanup

On entity delete, call DELETE /storage/file/{storageFileId} to remove the blob and decrement metrics.

Configure

Provider credentials and module settings via MCP ?modules=storage:

ToolPurpose
get_config_storageRead provider, container, and CDN settings
patch_config_storageSet provider (aws / azure / google / aliyun / local), credentials, defaultContainer, allowContainerCreation, suffixOnNameConflict, cdnConfiguration

Key config fields:

FieldDefaultDescription
providerlocalActive storage backend
defaultContainerconduitContainer used when none is specified on upload
allowContainerCreationtrueAllow Client API to create containers on first use
suffixOnNameConflictfalseAppend (n) to filename when a duplicate exists
authorization.enabledfalseEnable ReBAC checks and scope parameter

Requires the database module (file metadata is stored as documents).

Client API

MethodPathAuth
POST/storage/uploadRequired
PATCH/storage/upload/:idRequired
POST/storage/fileRequired (base64 inline upload)
PATCH/storage/file/:idRequired (base64 inline update)
GET/storage/getFileUrl/:idOptional (redirect, download query params)
GET/storage/file/:idOptional (metadata document)
GET/storage/file/data/:idRequired (base64 — small server-side transforms only)
DELETE/storage/file/:idRequired

When authorization is enabled, add scope as a query parameter on mutating routes and reads of private files.

MCP

Enable ?modules=storage for provider and container configuration. Admin API routes under /storage/ expose container, folder, and file management for operators.

Next steps

  • Next.js integration
  • Chat attachments
  • Authorization & scope
  • Database linking

Database

Schemas, CRUD, custom endpoints, indexes, query trees, and GitOps export.

Communications

Unified email, SMS, and push — one module, three channels, orchestrated delivery.

On this page

Use casesCapabilitiesExample: Upload, link, and serve via preview proxyHow it worksConfigureClient APIMCP