Content

Assets & Images

CellCMS provides a complete asset pipeline for images and files with on-the-fly image transforms, metadata extraction, and pluggable storage backends.

Uploading Assets

Upload images and files via multipart form data:

curl -X POST https://api.cellcms.com/api/v1/assets/production \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -F "file=@photo.jpg"

Response:

{
  "_id": "asset-uuid",
  "_type": "image",
  "assetId": "asset-uuid",
  "path": "project-id/production/asset-uuid.jpg",
  "url": "/api/v1/assets/asset-uuid",
  "metadata": {
    "width": 1920,
    "height": 1080,
    "format": "jpeg",
    "hasAlpha": false,
    "palette": {
      "dominant": "#2b5797",
      "vibrant": "#ff6600"
    }
  }
}

Limits:

  • Maximum file size: 50 MB
  • Supported image formats: JPEG, PNG, WebP, AVIF, GIF, TIFF, SVG
  • Any file type can be uploaded (PDFs, videos, etc.) — image transforms only apply to supported image formats

Uploading via the Client SDK

// The client SDK doesn't have a built-in upload method,
// but you can use the fetch API directly:
const formData = new FormData()
formData.append('file', fileInput.files[0])

const response = await fetch(
  `${apiUrl}/api/v1/assets/production`,
  {
    method: 'POST',
    headers: { Authorization: `Bearer ${token}` },
    body: formData,
  }
)

const asset = await response.json()

Uploading via Studio

In the document editor, click on an image or file field to open the upload dialog. You can drag and drop files or click to browse.


Image Transforms

CellCMS transforms images on the fly using Sharp. Add query parameters to any asset URL to get a transformed version.

Transform Parameters

ParameterTypeDescriptionExample
wnumberWidth in pixels?w=400
hnumberHeight in pixels?h=300
fitstringResize behavior?fit=cover
formatstringOutput format?format=webp
qnumberQuality (1–100)?q=80
blurnumberGaussian blur radius?blur=10
dprnumberDevice pixel ratio?dpr=2

Fit Modes

ModeDescription
coverCrop to fill the exact dimensions (default)
containResize to fit within dimensions, preserving aspect ratio
fillStretch to fill exact dimensions

Output Formats

FormatBest For
webpModern browsers, best compression
avifModern browsers, smallest files
jpegUniversal compatibility
pngTransparency, lossless

Examples

Thumbnail (200×200, cropped):

/api/v1/assets/abc123?w=200&h=200&fit=cover

Responsive hero image (WebP, 80% quality):

/api/v1/assets/abc123?w=1200&format=webp&q=80

Retina display (2x DPR):

/api/v1/assets/abc123?w=400&dpr=2

This delivers an 800px image that displays at 400px on retina screens.

Blurred placeholder:

/api/v1/assets/abc123?w=20&blur=10&q=30

Format conversion (PNG → WebP):

/api/v1/assets/abc123?format=webp&q=85

Responsive Images in HTML

<picture>
  <source
    srcset="/api/v1/assets/abc123?w=800&format=avif&q=80"
    type="image/avif"
  />
  <source
    srcset="/api/v1/assets/abc123?w=800&format=webp&q=80"
    type="image/webp"
  />
  <img
    src="/api/v1/assets/abc123?w=800&q=85"
    srcset="
      /api/v1/assets/abc123?w=400&q=80 400w,
      /api/v1/assets/abc123?w=800&q=80 800w,
      /api/v1/assets/abc123?w=1200&q=80 1200w
    "
    sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
    alt="Description"
    loading="lazy"
  />
</picture>

Metadata

When an image is uploaded, CellCMS automatically extracts metadata using Sharp:

{
  "width": 1920,
  "height": 1080,
  "format": "jpeg",
  "hasAlpha": false,
  "palette": {
    "dominant": "#2b5797",
    "vibrant": "#ff6600"
  }
}
FieldDescription
widthImage width in pixels
heightImage height in pixels
formatDetected format (jpeg, png, webp, etc.)
hasAlphaWhether the image has an alpha channel
paletteExtracted color palette (dominant and vibrant colors)

This metadata is stored with the asset record and returned in list and detail endpoints.


Caching

Transformed images are cached for optimal performance:

  • Cache headers: Cache-Control: public, max-age=31536000, immutable (1 year)
  • ETag support: Returns 304 Not Modified when the asset hasn't changed
  • Transform cache: Transformed versions are cached in storage after first request
  • Cache key: Based on asset ID + transform parameters

The immutable cache policy means browsers and CDNs will cache transformed images indefinitely. Since asset URLs include the asset ID, uploading a new version creates a new URL automatically.


Storage Configuration

CellCMS supports two storage backends:

Local Storage (Default)

Files are stored on the local filesystem:

STORAGE_TYPE=local
STORAGE_LOCAL_PATH=./uploads

In Docker, uploads are persisted in a named volume (cellcms-uploads).

S3-Compatible Storage

Store files in Amazon S3, Cloudflare R2, MinIO, or any S3-compatible service:

STORAGE_TYPE=s3
S3_BUCKET=my-cellcms-assets
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-key

For Cloudflare R2 or MinIO, set the custom endpoint:

S3_ENDPOINT=https://your-account.r2.cloudflarestorage.com

Storage Key Format

Assets are stored with the key pattern:

{projectId}/{dataset}/{assetId}{extension}

Example: proj-uuid/production/asset-uuid.jpg


Listing Assets

List all assets in a dataset:

curl "https://api.cellcms.com/api/v1/assets/production/list?type=image&limit=20" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response:

{
  "items": [
    {
      "id": "asset-uuid",
      "type": "image",
      "filename": "hero.jpg",
      "mime_type": "image/jpeg",
      "size": 245760,
      "url": "/api/v1/assets/asset-uuid",
      "metadata": { "width": 1920, "height": 1080 },
      "created_at": "2025-01-15T10:00:00Z"
    }
  ],
  "total": 42
}

Filter by type: ?type=image or ?type=file

Paginate with ?limit=20&offset=40


Deleting Assets

curl -X DELETE https://api.cellcms.com/api/v1/assets/production/asset-uuid \
  -H "Authorization: Bearer YOUR_TOKEN"

This removes the file from storage and the record from the database.


Using Assets in Documents

Reference uploaded assets in your document content:

{
  "_type": "post",
  "title": "My Post",
  "coverImage": {
    "_type": "image",
    "asset": {
      "_ref": "asset-uuid",
      "_type": "reference"
    },
    "hotspot": {
      "x": 0.5,
      "y": 0.3,
      "width": 0.8,
      "height": 0.6
    }
  }
}

The hotspot field defines the focal point and crop region for the image, ensuring important content stays visible at any aspect ratio.