Cloudinary

Cloudinary asset CDN via the official Node SDK. Defaults to resource_type: raw for arbitrary-bytes storage; switch to image/video for transforms.

Installation

cloudinary is an optional peer dependency of files-sdk - install alongside the SDK so the adapter's imports resolve at runtime.

npm install files-sdk cloudinary

Usage

Cloudinary asset CDN via the official cloudinary Node SDK. Defaults to resource_type: "raw" for arbitrary-bytes storage so keys round-trip cleanly through the adapter; switch to "image" or "video" if you want Cloudinary's transformation features. Falls back to CLOUDINARY_URL or individual env vars when no explicit credentials are passed.

import { Files } from "files-sdk";
import { cloudinary } from "files-sdk/cloudinary";

const files = new Files({
  adapter: cloudinary({
    // Auto-loads from CLOUDINARY_URL (cloudinary://key:secret@cloud)
    // or CLOUDINARY_CLOUD_NAME + CLOUDINARY_API_KEY + CLOUDINARY_API_SECRET.
    //
    // Defaults to resource_type: "raw" - closest to S3-style
    // arbitrary-bytes storage. Switch to "image" / "video" if the
    // bucket holds those types and you want transforms.
    resourceType: "raw",
    type: "upload",
  }),
});

Options

Prop

Type

Limitations

Cloudinary's SDK keeps configuration as module-level global state, so mounting multiple cloudinary() adapters in the same process with different credentials will see only the last config win - use the client escape hatch with separately configured SDK instances if you need that.

Compatibility

MethodStatusNotes
upload⚠️Bodies are buffered into memory and handed to upload_stream - Cloudinary's SDK has no streaming form. User metadata and cacheControl throw - Cloudinary has no per-asset HTTP cache header and no arbitrary-metadata field on upload; drop to raw for context. Uploads are scoped to the adapter's resourceType/type and overwrite (invalidate: true).
download⚠️No streaming primitive - the adapter fetches the delivery URL with fetch() to read bytes, so streamed downloads still buffer the body in memory. Metadata comes from a parallel api.resource call.
delete
list⚠️Page size clamped to 500 (Cloudinary Admin API ceiling). Resources are scoped by resource_type and type at adapter construction, so mixed-type buckets need separate adapters. Pagination uses Cloudinary's opaque next_cursor.
search⚠️Built on listAll — inherits this adapter's list behavior above. Client-side key match (glob, regex, substring, exact).
head
exists
copy⚠️Re-upload by URL - Cloudinary has no native copy and rename is move-only. The adapter fetches the source delivery URL and ingests it as a new asset under to. Produces a new asset_id/etag, not a byte-identical reference. Costs an egress + an ingest; not atomic.
url⚠️Public delivery URLs by default (type: 'upload'). For private/authenticated types, mints a signed delivery URL via private_download_url (requires apiSecret and the asset's stored format - costs a HEAD round-trip per call). responseContentDisposition always throws - Cloudinary has no per-request Content-Disposition override (drop to raw for the attachment flag).
signedUploadUrl⚠️Form-POST shape with fields (method: 'POST'), not a single presigned PUT URL - signs Cloudinary's api_sign_request payload. Requires apiSecret. maxSize and minSize aren't enforced server-side - use an upload preset with max_file_size if you need a cap. expiresIn is informational - Cloudinary signatures are fixed at 1h.

On this page