---
title: "Cloudinary"
description: "Cloudinary as a planned MainSDK media driver - image and video transforms, setup, main.yaml, works on files from any files driver, and swapping."
section: "integrations"
canonical: "https://mainsdk.dev/docs/integrations/cloudinary"
updated: "2026-10-28"
---

# Cloudinary

> Cloudinary as a planned MainSDK media driver - image and video transforms, setup, main.yaml, works on files from any files driver, and swapping.

Canonical: https://mainsdk.dev/docs/integrations/cloudinary · Updated: 2026-10-28

Cloudinary is a hosted service that stores, transforms and delivers images and video. It is listed as a planned driver behind [`media`](https://mainsdk.dev/docs/interfaces/media), which resizes images and transcodes video with location data stripped. You would pick it for a wide range of on-the-fly image transforms and a delivery network in front of them.

> **Note:** `media` works on files from any [`files`](https://mainsdk.dev/docs/interfaces/files) driver (ADR-0013). Source files stay in `files`; Cloudinary only holds the processed copies.

> **Note:** `media` has no spec yet. The calls and options on this page are provisional, taken from the catalog and the product requirements, and may change when the spec lands.

## Interfaces it serves

### Images, video and audio (`media`)

- Status: Building for 0.4 · ships as a beta API
- Driver: `cloudinary` (Cloudinary)
- Docs: https://mainsdk.dev/docs/interfaces/media.md

```yaml
media:
  driver: cloudinary
```

Swap to another provider: `getqr`, `mux`, `ffmpeg`, `local`.

## Before you start

1. Create a Cloudinary account. Cloudinary identifies your account by a cloud name, with an API key and secret for server calls.
2. Decide which transforms you need and whether Cloudinary should store originals. With MainSDK, originals stay in getqr.id through [`files`](https://mainsdk.dev/docs/interfaces/files).
3. Store the API secret in your secrets manager.

## Configure

```yaml title="main.yaml"
media:
  driver: cloudinary
```

How the driver takes the cloud name and keys (as `secret:` references, for example `secret:CLOUDINARY_API_SECRET`) is not defined yet [TBD].

## Use it

```ts title="lib/avatar.ts"
import { media } from "mainsdk/media";

export async function avatarSizes(photoId: string) {
  const [small, large] = await Promise.all([
    media.image(photoId, { width: 64 }),
    media.image(photoId, { width: 512 }),
  ]);
  return { small, large };
}
```

The photo comes from `files.upload()`, private to its owner and scanned before it is readable. What `media.image()` returns is [TBD].

## Local development and testing

`media` ships in phase 2. The testing kit's in-memory fake for `media` arrives with its spec, so `createTestApp()` from `@mainsdk/testing` and `chaos.on("media", { outage: true })` cover it from then. Until then, use the `getqr` driver with a getqr.id sandbox key.

## What MainSDK adds on top

- Location data stripped from images and video, whichever driver runs.
- Source files stay in `files`: owner-scoped, scanned and stored by your `files` driver.
- The same `media.image()` and `media.video().transcode()` calls on every driver.

See [Images and video](https://mainsdk.dev/docs/interfaces/media).

## Limits and notes

- Planned driver, not in the spec yet. `media` has no spec and is phase 2.
- Works on files from any `files` driver (ADR-0013). Whether Cloudinary stays as a `media` driver is not decided, because `media` has no spec.
- Cloudinary would receive the images you transform. Check where it processes and stores them against your MainSDK data region (US, EU or India).

## Swap to or from it

```yaml title="main.yaml"
media:
  driver: cloudinary   # was getqr
```

Your `media` calls stay the same. Originals stay in `files`, so no files move; processed copies held by Cloudinary would be left behind and should be deleted when you switch back.

## FAQ

**Can I upload straight to Cloudinary from the browser?** No. Uploads go through `files` to the store you chose, with `files.upload()` or `files.uploadUrl()`; importing a storage SDK in route code fails `mainsdk check` with `MAIN-FILES-0010`.

**Should I use Cloudinary today?** `media` is phase 2 and has no spec, so the driver does not exist yet. Use the default `getqr` driver until it does.

## Next

- [Images and video](https://mainsdk.dev/docs/interfaces/media) and [File uploads](https://mainsdk.dev/docs/interfaces/files)
- [getqr.id](https://mainsdk.dev/docs/integrations/getqr-id) and [Mux](https://mainsdk.dev/docs/integrations/mux)
