Build with Sanity MCP in Replit. Prizes up for grabs! Submit by June 14

Sirv media source

Add Sirv as a first-class media source inside Sanity Studio. Connect your Sirv account, browse the Sirv DAM, and pick images, videos, 360 spins, Sirv views or any file directly from fields. Assets stay on Sirv and render on the frontend with the companion @sirv/react package.

By Jake Brumby

Install command

npm i @sirv/sanity-plugin

Sirv for Sanity

Add Sirv as a media source inside Sanity Studio v3, v4 and v5. Connect your Sirv account to browse your Sirv DAM (folders, search, thumbnails) and pick images, videos, 360 spins or any file to add to your page.

Your Sirv assets stay on Sirv (you store the path + delivery domain + dimensions) and render on the frontend with the companion package @sirv/react. It includes automatically scaled images to suit each users' device, lazy loading, image zoom, 360 spins, galleries, GLB models and video streaming.

  • No backend required - Sanity Studio talks directly to Sirv's REST API.
  • No credentials exposed - REST credentials are encrypted in the dataset's secrets.
  • Self-host friendly - designed for a locally-run / self-hosted Studio.

Packages

PackageWhat it is
@sirv/sanity-pluginThe Studio plugin: Asset Source, sirvMedia field type, Settings tool.
@sirv/reactFrontend renderers + next/image loader.
@sirv/coreHost-agnostic DAM browser, login UI, auth hook, types (no Sanity code).
@sirv/sirv-clientFramework-agnostic Sirv REST client (user-auth + DAM + account).
@sirv/url-builderPure Sirv transformation URL/srcset builders.

5-minute getting started

1. Install the plugin in your Studio

npm install @sirv/sanity-plugin
// sanity.config.ts
import { defineConfig } from 'sanity'
import { sirv } from '@sirv/sanity-plugin'

export default defineConfig({
  // ...
  plugins: [sirv()],
})

Use a private dataset - the plugin stores your Sirv credentials in a secrets.sirv document that must not be publicly readable.

2. Connect your account

Open the Sirv tool (or pick any image field), and sign in with your Sirv email + password (+ OTP if you have MFA), then choose an account. Tokens persist; later sessions are silent.

3a. Pick images on any image field (Asset Source)

Click Select on a standard image field and choose Sirv. The DAM browser opens; pick an image and it's stored as a normal Sanity image.

3b. Or use the sirvMedia field for video / spins / views + transforms

import { defineField } from 'sanity'

defineField({
  name: 'hero',
  type: 'sirvMedia',
  options: { allowedTypes: ['image', 'video', 'spin'] }, // omit to allow all four
})

This stores a richer value with the asset type, dimensions, alt text, and per-asset transformations.

4. Render on the frontend

npm install @sirv/react
import { SirvImage, SirvMedia, fromSanityMedia } from '@sirv/react'

// A standard responsive image:
<SirvImage alias="your.sirv.com" path="/products/shoe.jpg" width={800} alt="Shoe" />

// A stored sirvMedia value (any type):
<SirvMedia value={fromSanityMedia(doc.hero)} width={800} />

For next/image, point images.loaderFile at a file that re-exports { sirvLoader as default } from '@sirv/react/next'.

See examples/studio and examples/next for runnable references.

Architecture

apps/sanity-plugin   ->  @sirv/core  ->  @sirv/sirv-client
                     |               \-> @sirv/url-builder
                     ->  @sirv/react ->  @sirv/url-builder

One-way contract: apps/sanity-plugin depends on packages/*, never the reverse, and packages/* may not import Sanity. This is what makes the planned Contentful and Storyblok ports cheap (see docs/porting-to-contentful-storyblok.md). It is enforced by a Biome rule and scripts/check-package-boundaries.mjs (also run as a Vitest test).

Further reading: docs/architecture.md, docs/sirv-api-notes.md, docs/cross-plugin-patterns.md, docs/dam-browser-port-notes.md.

Develop

pnpm install
pnpm typecheck      # tsc --noEmit across every package
pnpm test           # vitest (unit + RTL; live tests are gated)
pnpm lint           # biome
pnpm boundaries     # assert no Sanity imports in packages/*

Requires Node >= 18.15 and pnpm >= 10. (Running the example Studio needs a Sanity project; the example Next.js site needs Node >= 20.19.)

Live API tests

@sirv/sirv-client has live smoke tests gated behind env flags, run against a real account:

set -a; source .env.local; set +a
SIRV_LIVE=1 pnpm test:live

End-user auth never requires client_id/client_secret. A gitignored .env.local (SIRV_CLIENT_ID / SIRV_CLIENT_SECRET, template in .env.example) exists only for these developer/CI smoke tests.