api-cms-sanity
構造化されたコンテンツを効率的に管理できるプラットフォームで、独自のクエリ言語GROQを使って柔軟なデータ抽出やリアルタイム更新、画像処理などを行い、コンテンツ定義から配信まで一貫してサポートするSkill。
📜 元の英語説明(参考)
Structured content platform — GROQ queries, schema definitions, @sanity/client, Portable Text, image handling, real-time listeners, mutations, TypeGen
🇯🇵 日本人クリエイター向け解説
構造化されたコンテンツを効率的に管理できるプラットフォームで、独自のクエリ言語GROQを使って柔軟なデータ抽出やリアルタイム更新、画像処理などを行い、コンテンツ定義から配信まで一貫してサポートするSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o api-cms-sanity.zip https://jpskill.com/download/10230.zip && unzip -o api-cms-sanity.zip && rm api-cms-sanity.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/10230.zip -OutFile "$d\api-cms-sanity.zip"; Expand-Archive "$d\api-cms-sanity.zip" -DestinationPath $d -Force; ri "$d\api-cms-sanity.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
api-cms-sanity.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
api-cms-sanityフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
Sanity のパターン
クイックガイド: 構造化されたコンテンツ管理には Sanity を使用し、GROQ クエリ、
defineType/defineFieldを介した型付きスキーマ、データ取得には@sanity/clientを使用します。常にapiVersionを日付文字列に設定し、パブリック読み取りにはuseCdn: trueを使用し、ドラフトドキュメントを明示的に処理し、画像変換には@sanity/image-urlを使用し、リッチテキストのレンダリングには@portabletext/reactを使用します。TypeScript の型はsanity typegen generateで生成します。
<critical_requirements>
必須: この Skill を使用する前に
すべてのコードは、CLAUDE.md のプロジェクト規約に従う必要があります (kebab-case、名前付きエクスポート、インポート順序、
import type、名前付き定数)
(createClient で apiVersion を '2025-02-19' のような日付文字列に必ず設定する必要があります — 省略すると、互換性のないレガシー API が使用されます)
(パブリック読み取りクエリには useCdn: true を、トークンを使用する場合や最新のデータが必要な場合は useCdn: false を必ず使用する必要があります)
(動的な値には、パラメータ化された GROQ クエリ ($param) を必ず使用してください — ユーザー入力を GROQ 文字列に補間しないでください)
(ドラフトを明示的に処理する必要があります — ドラフトドキュメントの _id には drafts. がプレフィックスとして付加されており、デフォルトでは perspective: 'published' では返されません)
(TypeGen 型生成のために、groq の defineQuery() を必ず使用し、クエリを名前付き変数に割り当てる必要があります)
</critical_requirements>
自動検出: Sanity, sanity, @sanity/client, createClient, GROQ, groq, defineType, defineField, defineArrayMember, @sanity/image-url, urlFor, @portabletext/react, PortableText, portable text, block content, sanity.config, sanity.cli, typegen, sanity studio, content lake
使用する場面:
- データ取得のために
@sanity/clientをcreateClientでセットアップする - GROQ クエリ (フィルタ、プロジェクション、結合、順序付け、スライス) を記述する
defineType、defineField、defineArrayMemberでコンテンツスキーマを定義する@portabletext/reactで Portable Text (ブロックコンテンツ) をレンダリングする@sanity/image-urlで画像 URL を生成する (レスポンシブ画像、クロップ、ホットスポット)- ミューテーション (作成、パッチ、削除、トランザクション) を実行する
client.listen()でリアルタイムリスナーをセットアップする- Sanity TypeGen で TypeScript 型を生成する
カバーする主なパターン:
createClientとapiVersion構成によるクライアントのセットアップ- GROQ クエリ言語: フィルタ、プロジェクション、順序付け、スライス、結合、参照
- スキーマ定義: ドキュメント型、オブジェクト型、配列、参照、画像
- カスタムコンポーネントによる Portable Text のレンダリング
- レスポンシブ画像と変換による画像 URL ビルダー
- ミューテーション: 作成、createOrReplace、パッチ、削除、トランザクション
client.listen()によるリアルタイムリスナーdefineQuery()を使用した型安全な GROQ クエリのための TypeGen
使用しない場面:
- GraphQL のみの API (Sanity は主に GROQ をサポートしています。必要な場合は GraphQL skill を使用してください)
- 直接的なデータベースアクセス (Sanity はホストされた content lake であり、データベースではありません)
- Sanity 以外の CMS プラットフォーム (CMS 専用の skill を使用してください)
詳細なリソース:
- 意思決定フレームワークとクイックリファレンステーブルについては、reference.md を参照してください。
クライアント & GROQ:
- examples/core.md — クライアントのセットアップ、GROQ クエリ、エラー処理、TypeGen
スキーマ:
- examples/schemas.md — defineType, defineField, ドキュメント型、オブジェクト型、参照、画像
リッチコンテンツ:
- examples/rich-content.md — Portable Text のレンダリング、画像 URL ビルダー、レスポンシブ画像
ミューテーション & リアルタイム:
- examples/mutations.md — 作成、パッチ、削除、トランザクション、リアルタイムリスナー
<philosophy>
哲学
Sanity は、リアルタイムの content lake、クエリ言語としての GROQ (Graph-Relational Object Queries)、カスタマイズ可能な編集環境としての Sanity Studio を中心に構築された構造化コンテンツプラットフォームです。
コア原則:
- 構造化コンテンツ — コンテンツは、形状、検証、編集 UI を記述するスキーマ (
defineType,defineField) によって定義されます。スキーマはコードであり、構成ファイルではありません。 - GROQ ファーストのクエリ — GROQ を使用すると、単一のクエリでデータのフィルタリング、プロジェクション、結合、再形成を行うことができます。REST や GraphQL とは異なり、GROQ クエリはプロジェクションで定義した形状を正確に返します。
- データとしてのコンテンツ — リッチテキストは Portable Text (JSON ベースの仕様) として保存されるため、ベンダーロックインなしに、あらゆるフロントエンドフレームワークでレンダリングできます。
- API バージョニング — すべてのクライアントは
apiVersionの日付文字列を指定する必要があります。これにより、コードが特定の API 動作に固定され、破壊的な変更が本番環境に影響を与えるのを防ぎます。 - CDN キャッシュ — パブリック読み取りクエリは、エッジキャッシュされたレスポンスのために
useCdn: trueを使用します。ミューテーションと認証された読み取りは、最新のデータのためにuseCdn: falseを使用します。 - 型生成 — Sanity TypeGen は、スキーマと GROQ クエリの両方から TypeScript 型を生成し、コンテンツモデルからフロントエンドまで、エンドツーエンドの型安全性を実現します。
Sanity を使用する場面:
- コンテンツ主導のウェブサイトおよびアプリケーション (ブログ、マーケティングサイト、ドキュメント)
- カスタマイズ可能なスタジオでのリアルタイムの共同編集を必要とするプロジェクト
- 単一のコンテンツソースからのマルチチャネルコンテンツ配信 (ウェブ、モバイル、IoT)
- GROQ と TypeGen による型安全なコンテンツクエリを必要とするチーム
使用しない場面:
- ACID 保証を必要とするトランザクションデータ (データベースを使用してください)
- 大規模なユーザー生成コンテンツ (Sanity は編集コンテンツに最適化されています)
- セルフホスト型の CMS を必要とするプロジェクト (Sanity の content lake はホストされていますが、Studio はオープンソースです)
</philosophy>
<patterns>
コアパターン
パターン 1: createClient によるクライアントのセットアップ
プロジェクト ID、データセット、API バージョン、CDN の優先度を使用して @sanity/client を構成します。常に apiVersion を日付文字列に、useCdn を明示的に設定してください。
import { createClient } from "@sanity/client";
export const client = createClient({
projectId: process.env.SANITY_PROJECT_ID!,
dataset: process.env.SANITY_DATASET!,
apiVersion: "2025-02-19"
(原文がここで切り詰められています) 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Sanity Patterns
Quick Guide: Use Sanity for structured content management with GROQ queries, typed schemas via
defineType/defineField, and@sanity/clientfor data fetching. Always setapiVersionto a dated string, useuseCdn: truefor public reads, handle draft documents explicitly, use@sanity/image-urlfor image transformations, and render rich text with@portabletext/react. Generate TypeScript types withsanity typegen generate.
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST always set apiVersion on createClient to a dated string like '2025-02-19' — omitting it uses a legacy API that may break)
(You MUST use useCdn: true for public read queries and useCdn: false when using a token or needing fresh data)
(You MUST use parameterized GROQ queries ($param) for any dynamic values — never interpolate user input into GROQ strings)
(You MUST handle drafts explicitly — draft documents have _id prefixed with drafts. and are not returned by default with perspective: 'published')
(You MUST use defineQuery() from groq and assign queries to named variables for TypeGen type generation)
</critical_requirements>
Auto-detection: Sanity, sanity, @sanity/client, createClient, GROQ, groq, defineType, defineField, defineArrayMember, @sanity/image-url, urlFor, @portabletext/react, PortableText, portable text, block content, sanity.config, sanity.cli, typegen, sanity studio, content lake
When to use:
- Setting up
@sanity/clientwithcreateClientfor data fetching - Writing GROQ queries (filters, projections, joins, ordering, slicing)
- Defining content schemas with
defineType,defineField,defineArrayMember - Rendering Portable Text (block content) with
@portabletext/react - Generating image URLs with
@sanity/image-url(responsive images, crops, hotspots) - Performing mutations (create, patch, delete, transactions)
- Setting up real-time listeners with
client.listen() - Generating TypeScript types with Sanity TypeGen
Key patterns covered:
- Client setup with
createClientandapiVersionconfiguration - GROQ query language: filters, projections, ordering, slicing, joins, references
- Schema definitions: document types, object types, arrays, references, images
- Portable Text rendering with custom components
- Image URL builder with responsive images and transformations
- Mutations: create, createOrReplace, patch, delete, transactions
- Real-time listeners via
client.listen() - TypeGen for type-safe GROQ queries with
defineQuery()
When NOT to use:
- GraphQL-only APIs (Sanity supports GROQ primarily; use GraphQL skill if needed)
- Direct database access (Sanity is a hosted content lake, not a database)
- Non-Sanity CMS platforms (use the dedicated skill for your CMS)
Detailed Resources:
- For decision frameworks and quick-reference tables, see reference.md
Client & GROQ:
- examples/core.md — Client setup, GROQ queries, error handling, TypeGen
Schemas:
- examples/schemas.md — defineType, defineField, document types, object types, references, images
Rich Content:
- examples/rich-content.md — Portable Text rendering, image URL builder, responsive images
Mutations & Real-time:
- examples/mutations.md — Create, patch, delete, transactions, real-time listeners
<philosophy>
Philosophy
Sanity is a structured content platform built around a real-time content lake, GROQ (Graph-Relational Object Queries) as its query language, and Sanity Studio as a customizable editing environment.
Core principles:
- Structured content — Content is defined by schemas (
defineType,defineField) that describe shape, validation, and editorial UI. Schemas are code, not configuration files. - GROQ-first querying — GROQ lets you filter, project, join, and reshape data in a single query. Unlike REST or GraphQL, GROQ queries return exactly the shape you define in the projection.
- Content as data — Rich text is stored as Portable Text (a JSON-based specification), making it renderable in any frontend framework without vendor lock-in.
- API versioning — Every client must specify an
apiVersiondate string. This pins your code to a specific API behavior, preventing breaking changes from affecting production. - CDN caching — Public read queries use
useCdn: truefor edge-cached responses. Mutations and authenticated reads useuseCdn: falsefor fresh data. - Type generation — Sanity TypeGen generates TypeScript types from both your schemas and GROQ queries, enabling end-to-end type safety from content model to frontend.
When to use Sanity:
- Content-driven websites and applications (blogs, marketing sites, documentation)
- Projects needing real-time collaborative editing in a customizable studio
- Multi-channel content delivery (web, mobile, IoT) from a single content source
- Teams wanting type-safe content queries with GROQ and TypeGen
When NOT to use:
- Transactional data requiring ACID guarantees (use a database)
- User-generated content at massive scale (Sanity is optimized for editorial content)
- Projects needing a self-hosted CMS (Sanity's content lake is hosted, though the Studio is open source)
</philosophy>
<patterns>
Core Patterns
Pattern 1: Client Setup with createClient
Configure @sanity/client with project ID, dataset, API version, and CDN preference. Always set apiVersion to a dated string and useCdn explicitly.
import { createClient } from "@sanity/client";
export const client = createClient({
projectId: process.env.SANITY_PROJECT_ID!,
dataset: process.env.SANITY_DATASET!,
apiVersion: "2025-02-19", // Pin to a specific API version date
useCdn: true, // true for public reads, false for authenticated/fresh data
});
For dual client setup (public + preview with token), see examples/core.md.
Pattern 2: GROQ Queries with Filters and Projections
GROQ queries combine filters, projections, ordering, and slicing. Always use defineQuery() for TypeGen and $param for dynamic values.
import { defineQuery } from "groq";
const POST_BY_SLUG_QUERY = defineQuery(`
*[_type == "post" && slug.current == $slug][0]{
_id, title, body, "author": author->{name, image}
}
`);
const post = await client.fetch(POST_BY_SLUG_QUERY, { slug: "my-post" });
Never interpolate user input into GROQ strings -- always use $param parameters to prevent GROQ injection. For advanced queries (combined queries, conditional projections), see examples/core.md.
Pattern 3: Schema Definitions with defineType and defineField
Define content structure with defineType, defineField, and defineArrayMember from "sanity" for type safety and Studio UI.
import { defineType, defineField } from "sanity";
export const postType = defineType({
name: "post",
type: "document",
fields: [
defineField({
name: "title",
type: "string",
validation: (r) => r.required(),
}),
defineField({ name: "slug", type: "slug", options: { source: "title" } }),
],
});
For complete schemas (images with hotspot, arrays, references, previews, object types), see examples/schemas.md.
Pattern 4: Portable Text Rendering
Render block content with @portabletext/react. Define custom PortableTextComponents for non-standard blocks (images, code) and marks (links, highlights).
import { PortableText } from "@portabletext/react";
<PortableText value={body} components={components} />;
Do not use the deprecated @sanity/block-content-to-react package. For full component examples, see examples/rich-content.md.
Pattern 5: Image URL Builder
Use @sanity/image-url to generate optimized, responsive image URLs with crop and hotspot support.
import { createImageUrlBuilder } from "@sanity/image-url";
const builder = createImageUrlBuilder(client);
export function urlFor(source: SanityImageSource) {
return builder.image(source);
}
// Usage: urlFor(image).width(800).auto("format").url()
For responsive srcSet patterns and image transformations, see examples/rich-content.md.
Pattern 6: Mutations (Create, Patch, Delete)
Use @sanity/client methods for document mutations. Always call .commit() on patches and transactions.
await client.create({ _type: "post", title: "New Post" });
await client.patch("post-123").set({ title: "Updated" }).commit();
await client.delete("post-123");
For createOrReplace, createIfNotExists, transactions, array inserts, and visibility options, see examples/mutations.md.
Pattern 7: Real-Time Listeners
Subscribe to document changes with client.listen(). The listener only uses the filter portion of GROQ -- projections and ordering are ignored.
const subscription = client.listen(`*[_type == "post"]`).subscribe({
next: (update) => {
/* update.transition: 'update' | 'appear' | 'disappear' */
},
error: (err) => console.error(err),
});
subscription.unsubscribe(); // Cleanup when done
For production frontends, evaluate the newer Live Content API as a simpler alternative. For listener options and caveats, see examples/mutations.md.
Pattern 8: TypeGen for Type-Safe GROQ
Configure TypeGen in sanity.cli.ts with overloadClientMethods: true for typed client.fetch results. Use defineQuery() from "groq" to make queries discoverable by TypeGen.
// sanity.cli.ts — set typegen.overloadClientMethods: true
// queries/post-queries.ts — wrap queries with defineQuery()
// sanity.types.ts — auto-generated result types
const posts = await client.fetch(allPostsQuery); // Typed result
Inline query strings without defineQuery() produce untyped (any) results. For full TypeGen configuration and workflow, see examples/core.md.
</patterns>
<decision_framework>
Decision Framework
useCdn: true vs false
Is the data public and non-personalized?
├─ YES → useCdn: true (edge-cached, fast)
└─ NO →
├─ Using a token for authenticated reads? → useCdn: false
├─ Need real-time fresh data (preview)? → useCdn: false
└─ Performing mutations? → useCdn: false
Draft Handling
Do you need draft documents?
├─ YES → Use perspective: 'previewDrafts' (requires token)
├─ NO → Use perspective: 'published' (default since API v2025-02-19)
└─ Mixed (preview mode toggle)?
└─ Create two clients: one public (useCdn: true), one preview (token + useCdn: false)
GROQ Query Return Shape
How many documents do you expect?
├─ One (by ID, slug, singleton) → Add [0] at end (returns object or null)
├─ Many (list, feed) → No slice suffix (returns array)
└─ Paginated → Add [start...end] slice
Image Handling
How should images be delivered?
├─ Fixed size (thumbnails, avatars) → urlFor(img).width(W).height(H).url()
├─ Responsive (article images) → srcSet with multiple widths
├─ Format optimization → .auto('format') for WebP/AVIF
└─ Cropped to aspect ratio → .width(W).height(H).fit('crop')
Mutation Method Selection
What operation do you need?
├─ Create new document → client.create()
├─ Create or fully replace → client.createOrReplace() (for singletons)
├─ Create only if missing → client.createIfNotExists()
├─ Update specific fields → client.patch(id).set({...}).commit()
├─ Remove fields → client.patch(id).unset([...]).commit()
├─ Multiple related changes → client.transaction()...commit()
└─ Delete document → client.delete(id)
</decision_framework>
<red_flags>
RED FLAGS
High Priority Issues:
- Missing
apiVersionon client — OmittingapiVersionuses legacy API behavior that may change without notice. Always pin to a date string. - String interpolation in GROQ queries — Interpolating user input into GROQ strings enables GROQ injection. Always use
$paramparameters. - Using
useCdn: truewith a token — CDN-cached responses ignore authentication tokens. Authenticated queries must useuseCdn: false. - Accessing draft documents without a token — Drafts (
drafts.*documents) require an API token andperspective: 'previewDrafts'. Without a token, drafts are invisible.
Medium Priority Issues:
- Fetching all fields with
{...}when only a few are needed — Over-fetching wastes bandwidth and CDN cache efficiency. Project only the fields you need. - Missing
.commit()on patches —client.patch(id).set({...})without.commit()does nothing — the mutation is never sent. - Not using
defineQuery()for GROQ queries — TypeGen cannot generate types for queries that aren't wrapped indefineQuery()or assigned to named variables. - Hardcoded project ID or dataset — Use environment variables; hardcoded values prevent environment switching and leak project details.
- Using deprecated
@sanity/block-content-to-react— Replaced by@portabletext/react. The old package is unmaintained.
Common Mistakes:
- Forgetting
_keyon array items in mutations — Every item in a Sanity array must have a unique_keyfield. Mutations without_keywill fail. - Using
_idwithclient.create()—create()generates a random_id. If you specify_idand the document exists, it errors. UsecreateOrReplace()orcreateIfNotExists()for idempotent operations. - Not handling the case where
[0]returnsnull— A GROQ query ending in[0]returnsnullif no documents match, not an empty object. - Expecting
client.listen()to work with projections — The listener only uses the filter portion of a GROQ query. Projections, ordering, and slicing are ignored.
Gotchas & Edge Cases:
- API version
2025-02-19changed default perspective — Before this version, the default perspective wasraw(includes drafts). After, it defaults topublished. Existing code may break if you updateapiVersionwithout accounting for this. - CDN cache is eventual — After a mutation, CDN-cached queries (
useCdn: true) may return stale data for a few seconds. UseuseCdn: falseor add a small delay for consistency-critical reads after writes. - Slug fields store value in
.current— Queryslug.current, notslugdirectly.*[slug == "my-slug"]will never match. - Image fields require the full object for crop/hotspot — Passing only
asset._reftourlFor()works for basic URLs but loses crop and hotspot metadata. Pass the entire image field object. - Portable Text arrays need
_keyon every block — When creating Portable Text content programmatically, every block and inline object needs a unique_key. client.listen()reconnects automatically — But there's no built-in guarantee against missed events during reconnection. For critical use cases, combine with periodic re-fetching.- TypeGen requires
schema.jsonextraction first — Runnpx sanity schema extractbeforenpx sanity typegen generate. The extract step reads your Studio schemas and outputs a JSON representation.
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST always set apiVersion on createClient to a dated string like '2025-02-19' — omitting it uses a legacy API that may break)
(You MUST use useCdn: true for public read queries and useCdn: false when using a token or needing fresh data)
(You MUST use parameterized GROQ queries ($param) for any dynamic values — never interpolate user input into GROQ strings)
(You MUST handle drafts explicitly — draft documents have _id prefixed with drafts. and are not returned by default with perspective: 'published')
(You MUST use defineQuery() from groq and assign queries to named variables for TypeGen type generation)
Failure to follow these rules will cause unpredictable API behavior, GROQ injection vulnerabilities, and untyped query results.
</critical_reminders>