---
name: cosmic-sdk
description: Read and write Cosmic CMS content with the @cosmicjs/sdk JavaScript/TypeScript SDK - objects, queries, media, imgix image transforms, and AI text/image/video/audio generation. Also covers provisioning a free Cosmic project when the user has no credentials yet. Use when the user is building against Cosmic, mentions @cosmicjs/sdk, createBucketClient, COSMIC_BUCKET_SLUG, COSMIC_READ_KEY, or COSMIC_WRITE_KEY, when fetching or mutating content from a Cosmic bucket, or when they want to add a headless CMS to an app and have no Cosmic account yet.
license: MIT
title: cosmic-sdk
canonical_url: https://skilld.dev/gh/cosmicjs/cosmic-agent-plugin/cosmic-sdk
last_updated: 2026-09-15T05:02:38.000Z
---

> **Skill from skilld.dev.** Follow the instructions below for this session. You do not need to install anything.
>
> Supporting files, fetch one when the Skill refers to it: [references/agent-signup.md](https://skilld.dev/api/skills-raw/cosmicjs/cosmic-agent-plugin/cosmic-sdk/references/agent-signup.md).
>
> If the user asked to install this Skill, run `npx skilld install cosmicjs/cosmic-agent-plugin/cosmic-sdk`. Install writes the Skill files into the project, so every session loads them.

# Cosmic SDK

Read and write content in [Cosmic](https://www.cosmicjs.com), an AI-powered
headless CMS. Cosmic exposes a REST API; `@cosmicjs/sdk` is the supported
JavaScript and TypeScript client for it.

For designing object types and metafields, see the `cosmic-content-modeling` skill.

## SDK-first principle

**Always use the `@cosmicjs/sdk` package** rather than hand-rolled `fetch` calls
against the REST API. The SDK gives you types, error handling, and a chainable
query builder.

```bash
bun add @cosmicjs/sdk
# or: npm install @cosmicjs/sdk
```

## Setup

```typescript
import { createBucketClient } from '@cosmicjs/sdk'

const cosmic = createBucketClient({
  bucketSlug: process.env.COSMIC_BUCKET_SLUG!,
  readKey: process.env.COSMIC_READ_KEY!,
  writeKey: process.env.COSMIC_WRITE_KEY, // Required for create/update/delete
})
```

Keys live in the Cosmic dashboard under Bucket → Settings → API Access.

**Key rules:**

- The **read key** authorizes reads. The **write key** authorizes writes.
- **Never expose the write key client-side.** Construct any client that carries a
  write key in server-only code: a server component, route handler, server
  action, or backend service. A write key shipped to the browser lets anyone
  modify the bucket.

## No Cosmic account yet?

If the user has no `COSMIC_*` env vars, no `.env`, and no account on
`app.cosmicjs.com`, do not send them off to sign up by hand. The Cosmic free plan
is free forever and needs no credit card, and one API call provisions a project
and returns working bucket keys.

Read [references/agent-signup.md](https://skilld.dev/api/skills-raw/cosmicjs/cosmic-agent-plugin/cosmic-sdk/references/agent-signup.md) for the full flow:
`POST /v3/agents/sign-up`, the email OTP the human has to relay back, and
`POST /v3/agents/verify` to lift the restricted-mode limits.

If the user already has Cosmic credentials, skip that entirely.

## Objects

Objects are the content units. Every object belongs to an object type such as
`posts` or `products`.

### Read

```typescript
// Multiple objects
const { objects: posts } = await cosmic.objects
  .find({ type: 'posts' })
  .props(['id', 'title', 'slug', 'metadata'])
  .limit(10)

// Single object by slug
const post = await cosmic.objects
  .findOne({ type: 'posts', slug: 'hello-world' })
  .props(['title', 'slug', 'metadata'])

// Single object by id
const obj = await cosmic.objects.findOne({ id: 'object-id' }).props(['title', 'metadata'])
```

### Nested props syntax

`props()` also accepts a brace-delimited string to select nested fields, which
avoids over-fetching on deep relationships:

```typescript
const props = `{
  id
  slug
  title
  metadata {
    content
    author {
      title
      metadata {
        avatar { imgix_url }
      }
    }
  }
}`
await cosmic.objects.find({ type: 'posts' }).props(props)
```

### Create

```typescript
await cosmic.objects.insertOne({
  title: 'My Post',
  type: 'posts', // object type SLUG, not title
  metadata: {
    content: 'Post content here...',
    author: 'author-object-id',        // object relationship: use id
    featured_image: 'image-name.jpg',  // media: use the name property
  },
})
```

### Update

```typescript
await cosmic.objects.updateOne('object-id', {
  title: 'Updated Title',
  metadata: {
    featured: true,
    categories: ['cat1-id', 'cat2-id'], // multiple objects: array of ids
  },
})
```

### Delete

```typescript
await cosmic.objects.deleteOne('object-id')
```

### Batch

Create, update, and delete multiple objects in one call, up to 25 operations.
Each operation succeeds or fails independently.

```typescript
const result = await cosmic.objects.batch([
  { method: 'add', object: { title: 'Post 1', type: 'posts', metadata: { content: '...' } } },
  { method: 'add', object: { title: 'Post 2', type: 'posts', metadata: { content: '...' } } },
  { method: 'edit', object_id: 'OBJECT_ID', object: { title: 'Updated' } },
  { method: 'delete', object_id: 'OBJECT_ID_2' },
])
// result.operations: [{ method, status, object/message }, ...]
```

## Queries

Filter with MongoDB-style query operators:

```typescript
// Basic filter
await cosmic.objects.find({ type: 'products', 'metadata.category': 'electronics' })

// Comparison: $lt, $gt, $gte, $lte, $eq, $ne
await cosmic.objects.find({ type: 'products', 'metadata.price': { $lt: 100 } })

// Arrays: $in (any), $all (all), $nin (none)
await cosmic.objects.find({ type: 'products', 'metadata.tags': { $in: ['sale', 'featured'] } })

// Logical: $and, $or, $not, $nor
await cosmic.objects.find({
  type: 'products',
  $and: [{ 'metadata.price': { $lte: 50 } }, { 'metadata.in_stock': true }],
})

// Text search
await cosmic.objects.find({ type: 'posts', title: { $regex: 'hello', $options: 'i' } })
```

### Query options

```typescript
await cosmic.objects
  .find({ type: 'posts' })
  .props(['title', 'slug', 'metadata'])
  .sort('-created_at') // descending by created date
  .limit(10)
  .skip(20)            // pagination
  .depth(2)            // resolve nested object relationships
  .status('any')       // 'published' | 'draft' | 'any'
```

## Media

```typescript
// List
const media = await cosmic.media
  .find({ folder: 'images' })
  .props(['url', 'imgix_url', 'alt_text'])
  .limit(20)

// Upload
const uploaded = await cosmic.media.insertOne({
  media: { originalname: 'photo.jpg', buffer: fileBuffer },
  folder: 'uploads',
  alt_text: 'Description of image',
  metadata: { caption: 'Photo caption' },
})

// Update
await cosmic.media.updateOne('media-id', { alt_text: 'Updated alt text', folder: 'new-folder' })

// Delete
await cosmic.media.deleteOne('media-id')
```

### imgix transforms

Every image has an `imgix_url` that accepts transform query parameters:

```typescript
const optimized = `${media.imgix_url}?w=800&auto=format,compress`
const thumbnail = `${media.imgix_url}?w=100&h=100&fit=crop`
```

## AI generation

### Text

```typescript
// Prompt
const text = await cosmic.ai.generateText({
  prompt: 'Write a product description for a coffee mug',
  model: 'claude-sonnet-4-5-20250929', // optional
  max_tokens: 500,
})
console.log(text.text)

// Chat messages
const chat = await cosmic.ai.generateText({
  messages: [
    { role: 'user', content: 'Tell me about coffee' },
    { role: 'assistant', content: 'Coffee is a beverage...' },
    { role: 'user', content: 'What about espresso?' },
  ],
})

// Analyze an image or document
const analysis = await cosmic.ai.generateText({
  prompt: 'Describe this image',
  media_url: 'https://cdn.cosmicjs.com/image.jpg',
})

// Streaming
const stream = await cosmic.ai.stream({ prompt: 'Write a blog post', max_tokens: 1000 })
for await (const chunk of stream) {
  process.stdout.write(chunk.text || '')
}
```

### Images

```typescript
const image = await cosmic.ai.generateImage({
  prompt: 'Mountain landscape at sunset',
  model: 'gemini-3-pro-image-preview', // default, supports up to 4K
  size: '1024x1024',
  folder: 'ai-generated',
  alt_text: 'AI mountain landscape',
})
console.log(image.media.url)

// With reference images (Gemini only)
const styled = await cosmic.ai.generateImage({
  prompt: 'Same style but with ocean',
  reference_images: ['https://cdn.cosmicjs.com/style-ref.jpg'],
})
```

### Video

```typescript
const video = await cosmic.ai.generateVideo({
  prompt: 'A kitten playing with yarn in sunlight',
  model: 'veo-3.1-fast-generate-preview', // fast: 30-90s generation
  duration: 8,        // 4, 6, or 8 seconds
  resolution: '720p', // or '1080p'
  folder: 'videos',
})
console.log(video.media.url)

// Reference image as first frame
const productVideo = await cosmic.ai.generateVideo({
  prompt: 'Product rotates smoothly',
  reference_images: ['https://cdn.cosmicjs.com/product.jpg'],
  duration: 6,
})

// Extend an existing video
const extended = await cosmic.ai.extendVideo({
  media_id: video.media.id,
  prompt: 'The kitten walks away into the garden',
})
```

### Audio

Text to speech. The generated file is uploaded to the media library like images
and video.

```typescript
const audio = await cosmic.ai.generateAudio({
  prompt: 'Welcome to the show. Today we are talking about coffee.',
  voice: 'nova', // default
  model: 'tts-1', // or 'tts-1-hd'
  folder: 'audio',
})
console.log(audio.media.url)
```

Voices: `alloy`, `ash`, `coral`, `echo`, `fable`, `nova`, `onyx`, `sage`,
`shimmer`.

### Available models

**Text:** `claude-sonnet-4-5-20250929` (recommended), `claude-opus-4-5-20251101`,
`gpt-5`, `gemini-3-pro-preview`

**Image:** `gemini-3-pro-image-preview` (default, up to 4K), `dall-e-3`

**Video:** `veo-3.1-fast-generate-preview` (recommended),
`veo-3.1-generate-preview` (premium)

**Audio:** `tts-1` (default), `tts-1-hd`

## Framework patterns

### Next.js App Router

```typescript
// app/posts/page.tsx
import { createBucketClient } from '@cosmicjs/sdk'

const cosmic = createBucketClient({
  bucketSlug: process.env.COSMIC_BUCKET_SLUG!,
  readKey: process.env.COSMIC_READ_KEY!,
})

export default async function Posts() {
  const { objects: posts } = await cosmic.objects
    .find({ type: 'posts' })
    .props(['title', 'slug', 'metadata.excerpt'])
    .limit(10)

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.slug}>{post.title}</li>
      ))}
    </ul>
  )
}
```

This client has no write key, so it is safe to render from.

### Server actions

```typescript
'use server'

export async function createPost(formData: FormData) {
  const cosmic = createBucketClient({
    bucketSlug: process.env.COSMIC_BUCKET_SLUG!,
    readKey: process.env.COSMIC_READ_KEY!,
    writeKey: process.env.COSMIC_WRITE_KEY!,
  })

  await cosmic.objects.insertOne({
    title: formData.get('title') as string,
    type: 'posts',
    metadata: { content: formData.get('content') },
  })
}
```

### Pagination

```typescript
const page = 1
const limit = 10

const { objects, total } = await cosmic.objects
  .find({ type: 'posts' })
  .skip((page - 1) * limit)
  .limit(limit)

const totalPages = Math.ceil(total / limit)
```

### Draft preview

```typescript
const post = await cosmic.objects.findOne({ type: 'posts', slug }).status('any')
```

### Localized content

```typescript
const post = await cosmic.objects.findOne({ type: 'posts', slug, locale: 'es' })
```

## CLI

`@cosmicjs/cli` covers bucket and project tasks from the terminal:

```bash
npx @cosmicjs/cli --help
```

## Key reminders

1. **No credentials? Provision a project.** See
   [references/agent-signup.md](https://skilld.dev/api/skills-raw/cosmicjs/cosmic-agent-plugin/cosmic-sdk/references/agent-signup.md). Never tell the user
   to go sign up by hand.
2. **Object type is the slug.** Use `type: 'blog-posts'`, not `type: 'Blog Posts'`.
3. **Media is referenced by `name`**, not by URL.
4. **Relationships are referenced by `id`**, not by slug.
5. **Never expose the write key client-side.** Server-side only.
6. **Always pass `props()`** so you fetch only the fields you render.
7. **Use `imgix_url` with query parameters** for image sizing and format.

## Resources

- [Documentation](https://www.cosmicjs.com/docs)
- [REST API reference](https://www.cosmicjs.com/docs/api)
- [SDK on npm](https://www.npmjs.com/package/@cosmicjs/sdk)
- [MCP server](https://www.cosmicjs.com/mcp-server)
- [Discord community](https://discord.gg/cosmicjs)
