
Sanity CMSガイド:10言語で公開するための実践的な活用方法
私たちはSanity CMSを通じて、4つのウェブサイトと10言語で400以上のコンテンツ記事を公開してきました。スキーマ設計から自動化された多言語公開に至るまで、そこで学んだことを紹介します。
Sanity CMSは、構造化されたコンテンツ、リアルタイムのContent Lake、そしてSanity Studioと呼ばれるカスタマイズ可能なReactベースのエディタを中心に構築されたヘッドレスコンテンツプラットフォームです。クエリにはGROQを、リッチコンテンツにはPortable Textを、コンテンツモデリングにはスキーマアズコードを採用しています。このガイドでは、セットアップ、スキーマ設計、GROQ、Portable Text、多言語アーキテクチャ、および価格設定について解説します。
Sanity CMSとは?
Sanityは構造化されたコンテンツプラットフォームであり、Sanity.ioのチームが「コンテンツオペレーティングシステム」と呼ぶものです。HTMLの塊をデータベースに保存する従来のCMSとは異なり、SanityはContent Lakeと呼ばれる管理型バックエンドですべてのコンテンツを構造化されたJSONとして保存します。GROQまたはGraphQLでクエリを実行し、Next.js、React Native、Svelte、モバイルアプリ、CLIツールなど、任意のフロントエンドでコンテンツをレンダリングできます。
利用している企業は多岐にわたります。Nike、Figma、Puma、Cloudflareなどはエンタープライズ規模でSanityを運用しています。スタートアップ企業が利用するのは、無料枠が実際に使えるためです(価格については後述)。私たちがSanityを選んだ理由は、完全に自動化された10言語の公開パイプラインを構築できる柔軟性を提供してくれる唯一のプラットフォームだったからです。
Content Lakeアーキテクチャ
Content LakeはSanityの管理型バックエンドです。すべての接続されたクライアント間でリアルタイムに同期されるホスト型ドキュメントストアと考えてください。エディタがSanity Studioで段落を変更すると、別のエディタは即座にそれを目にします。保存ボタンも、マージの競合も、データベースの移行も不要です。
内部では、ドキュメントは型付けされたフィールドを持つ構造化JSONとして保存されます。すべての変更はトランザクションログを通じて追跡されるため、デフォルトで完全なバージョン履歴が利用できます。リアルタイム同期はリスナーベースのアーキテクチャ(SanityのGitHubアーキテクチャドキュメントで説明されています)を使用しており、RxJSオブザーバブルを通じてすべてのサブスクライバーに変更をプッシュします。
これがREST APIを備えたPostgreSQLデータベースなどとどう違うのでしょうか? Content Lakeは、コンテンツモデリング、アクセス制御、CDNキャッシング、画像変換、リアルタイムコラボレーションを単一の管理サービスとして処理します。移行を実行する必要はありません。レプリカを管理する必要もありません。スキーマを定義してコンテンツをクエリするだけです。
Sanity Studio:カスタマイズ可能なエディタ
Sanity Studioは、編集インターフェースとして機能するオープンソースのReactアプリケーションです。ホストされた管理パネルではなく、コードベース内に存在するReactアプリです。カスタム入力コンポーネント、条件付きフィールド、ドキュメントアクション、ストラクチャビルダーパターン、プラグインなど、あらゆる側面をカスタマイズできます。
リアルタイムコラボレーション機能が組み込まれています。複数のエディタが、プレゼンスインジケーターとライブアップデートを伴いながら、同時に同じドキュメントで作業できます。Google Docsを使用したことがあれば、その体験は似ています。他の人のカーソルや変更がリアルタイムで見えます。
私たちはnpx sanity deployを使用してStudioをデプロイしており、これはカスタムサブドメインでSanityのCDN上でホストされます。単なるReactアプリなので、セルフホスティングすることも可能です。Studioの柔軟性のおかげで、Sanityは私たちのヘッドレスCMS比較で高く評価されました。
Sanityプロジェクトのセットアップ方法
Sanity CMSをセットアップするには、npm create sanity@latestでCLIをインストールし、プロジェクトテンプレートを選択し、スキーマファイルを設定して、npx sanity devを実行してローカルでStudioを起動します。全体のプロセスは5分以内で完了します。
前提条件とインストール
必要なのはNode.js 18以上とnpm(またはpnpm)だけです。初期化コマンドを実行します。
npm create sanity@latest
# You'll be prompted for:
# - Login method (Google, GitHub, email)
# - Project name
# - Dataset name (default: "production")
# - Project template (blog, ecommerce, clean)
# - TypeScript? (recommended: yes)CLIが必要なものをすべて備えたプロジェクトのスキャフォールディングを行います。プロジェクト構造は以下のようになります。
プロジェクト構造の説明
my-sanity-project/
├── schemas/ # Your content schemas (this is where you'll spend time)
│ ├── index.ts # Schema registry -- imports and exports all types
│ ├── post.ts # Document type definitions
│ └── blockContent.ts # Rich text / Portable Text config
├── sanity.config.ts # Main config -- plugins, Studio structure, dataset
├── sanity.cli.ts # CLI config -- project ID, dataset
├── package.json
└── tsconfig.jsonsanity.config.tsファイルがエントリーポイントです。最小限の設定は以下の通りです。
// sanity.config.ts
import { defineConfig } from 'sanity'
import { structureTool } from 'sanity/structure'
import { visionTool } from '@sanity/vision'
import { schemaTypes } from './schemas'
export default defineConfig({
name: 'default',
title: 'My Blog',
projectId: 'your-project-id',
dataset: 'production',
plugins: [structureTool(), visionTool()],
schema: { types: schemaTypes },
})visionTool()プラグインにより、Studio内でGROQを試せるプレイグラウンドが利用可能になり、開発中に頻繁に使用することになります。
Studioのデプロイ
npx sanity devでローカルで起動します(localhost:3333で実行)。エディタと共有する準備ができたら、SanityのCDNにデプロイします。
npx sanity deploy
# Prompts for a hostname, e.g., "my-blog"
# Deploys to https://my-blog.sanity.studioプロのヒント:スキーマを変更した後は必ずnpx sanity@latest schema deployを実行してください。これによりスキーマがSanityのAPIにアップロードされ、GraphQL APIやスキーマ認識ツール(後で説明するMCPサーバーを含む)などの機能が有効になります。
Sanity CMSにおけるスキーマ設計
Sanityスキーマは、コードベース内のJavaScriptまたはTypeScriptオブジェクトとして定義されます。各スキーマは、フィールド、バリデーションルール、カスタム入力コンポーネントを持つドキュメントタイプを指定します。スキーマの変更は即座に反映され、データベースの移行は不要です。これが「スキーマアズコード」アプローチであり、ContentfulよりもSanityを選ばせた決め手となりました。
フィールドタイプとバリデーション
Sanityには豊富なフィールドタイプが用意されています。私たちが最もよく使用するものは以下の通りです。
| フィールドタイプ | 用途 | 例 |
|---|---|---|
string | 短いテキスト、タイトル、スラッグ | 投稿タイトル、著者名 |
text | 複数行のプレーンテキスト | 抜粋、説明 |
number | 整数、浮動小数点数 | 読了時間、ソート順 |
boolean | トグル | 特集フラグ、下書きステータス |
array | リスト、リッチテキスト(Portable Text) | 本文コンテンツ、タグ |
reference | 他のドキュメントへのリンク | 著者、カテゴリ |
image | メタデータ付き画像 | altテキスト付きカバー画像 |
slug | URLフレンドリーな文字列 | タイトルから自動生成 |
object | ネストされたフィールドグループ | SEOフィールド(metaTitle + metaDescription) |
date / datetime | 日付 | 公開日 |
すべてのフィールドはvalidationコールバックを通じてバリデーションをサポートします。必須フィールド、最小値/最大値、正規表現パターン、カスタムルールを強制できます。
defineField({
name: 'seoDescription',
title: 'Meta Description',
type: 'string',
validation: (Rule) =>
Rule.required()
.min(145)
.max(160)
.warning('Meta description should be 145-160 characters'),
})カスタムブロックタイプ(本番環境での例)
ここからSanityの面白さが見えてきます。競合する6つのガイドのうち、コードを示しているものは0でした。私たちの本番スキーマでは、body配列内に5つのカスタムブロックタイプを定義しています:block(標準テキスト)、table、codeBlock、chartBlock、inlineImage。
codeBlockの定義は以下の通りです。
// schemas/objects/codeBlock.ts
import { defineType } from 'sanity'
export const codeBlock = defineType({
name: 'codeBlock',
title: 'Code Block',
type: 'object',
fields: [
{
name: 'language',
title: 'Language',
type: 'string',
options: {
list: [
{ title: 'JavaScript', value: 'javascript' },
{ title: 'TypeScript', value: 'typescript' },
{ title: 'Python', value: 'python' },
{ title: 'Bash', value: 'bash' },
{ title: 'JSON', value: 'json' },
{ title: 'GROQ', value: 'groq' },
],
},
},
{
name: 'code',
title: 'Code',
type: 'text',
},
],
})そして、bodyフィールドがすべてのカスタムタイプを参照する方法は以下の通りです。
// schemas/fields/body.ts
defineField({
name: 'body',
title: 'Body',
type: 'array',
of: [
{ type: 'block' }, // Standard Portable Text (paragraphs, headings, lists)
{ type: 'table' }, // @sanity/table plugin
{ type: 'codeBlock' }, // Our custom code block
{ type: 'chartBlock' }, // Data visualization (bar, line, pie)
{ type: 'inlineImage' }, // Images with alt text and captions
],
})これにより、エディタは豊富なコンテンツツールキットを利用できつつ、すべての要素が型付けされ、クエリ可能になります。chartBlockは不透明なHTML埋め込みではなく、chartType、title、dataPoints、dataLabelsフィールドを持つ構造化データです。これは、Web、メール、モバイル across で同じコンテンツをレンダリングしようとする際に重要になります。
スキーマ整理のベストプラクティス
スキーマはモジュール化しておきましょう。私たちはタイプごとにファイルを分割しています:schemas/documents/post.ts、schemas/objects/codeBlock.ts、schemas/objects/chartBlock.ts。これらをすべてschemas/index.tsでインポートします。
// schemas/index.ts
import { post } from './documents/post'
import { codeBlock } from './objects/codeBlock'
import { chartBlock } from './objects/chartBlock'
import { inlineImage } from './objects/inlineImage'
export const schemaTypes = [post, codeBlock, chartBlock, inlineImage]構造化コンテンツを扱う中で得た重要な洞察:スキーマこそがあなたのコンテンツモデルです。これをコンテンツチームのためのコンテキストエンジニアリングと考えると、より良い設計判断を下せます。追加するすべてのフィールドは、エディタ、レンダリング、またはクエリのいずれかの目的を果たすべきです。
GROQ:Sanityのクエリ言語
GROQ(Graph-Relational Object Queries)は、JSONドキュメントのフィルタリング、結合、投影を行うためのSanityのオープンソースクエリ言語です。基本構文は*[filter]{projection}で、フィルターに一致するすべてのドキュメントを選択し、出力を整形します。Sanity固有のクエリにおいてはGraphQLよりも簡潔であり、私たちの経験では習得も迅速です。
基本クエリ:フィルタと投影
最もシンプルなクエリは、特定のタイプのすべてのドキュメントを取得します。
// Fetch all posts -- just title and slug
*[_type == "post"]{
title,
"slug": slug.current
}
// Filter by language, expand author reference
*[_type == "post" && language == "en"]{
title,
"slug": slug.current,
"authorName": author->name,
"authorImage": author->image,
"categoryTitle": category->title,
publishedAt
}->演算子は参照を追跡します。author->nameは「著者参照を追跡してnameフィールドを返す」ことを意味します。別々のクエリも、N+1問題も、JOINも不要です。すべてが1つの式で完結します。
結合、順序付け、ページネーション
ブログのインデックスページでは、展開された参照を含む順序付けられたページネーション済みの投稿が必要です。
// Paginated posts with full metadata
*[_type == "post" && language == "en"] | order(publishedAt desc) [0...10] {
title,
"slug": slug.current,
excerpt,
publishedAt,
readTime,
"author": author->{name, image},
"category": category->{title, "slug": slug.current},
"coverImage": coverImage{
"src": asset->url,
alt
}
}[0...10]は最初の10件の結果を返します(0から始まるインデックス、終端は除外)。| order(publishedAt desc)は新しい順にソートします。投影は、フロントエンドが必要とするものだけを正確に含めるように出力を整形します。
これらのクエリはすべて、Sanity Studio内のVisionプラグインを使用してインタラクティブにテストできます。開発中は invaluable です。さらに多くのパターンについては、GROQチートシートを確認してください。
GROQ vs GraphQL
SanityはGROQとGraphQLの両方をサポートしています。どちらを使うべきでしょうか?
GROQはSanityのネイティブ言語です。結合、投影、計算フィールドを単一のクエリ文字列で処理します。Content Lakeが最適化されているのもGROQです。
GraphQLは、スキーマをデプロイした後(npx sanity@latest schema deploy)に利用可能になります。標準化されたツールが必要な場合、例えばフロントエンドがすでにApollo Clientを使用している場合や、チームがGROQではなくGraphQLを知っている場合に使用します。
私たちは exclusively GROQを使用しています。Sanityデータに対してより表現力豊かであり、Visionプラグインによりクエリのデバッグが容易だからです。
Portable Text:リッチコンテンツの正しい扱い方
Portable Textは、構造化されたリッチテキストのためのSanityの仕様です。コンテンツをHTML文字列として保存するのではなく、 typed blocks、段落、見出し、画像、コードスニペット、テーブルなどをJSONオブジェクトとして配列で保存します。これにより、コンテンツは任意のフレームワーク、プラットフォーム、フォーマットでレンダリング可能になります。
データ構造
段落とコードブロックがPortable Text JSONとしてどのように見えるかは以下の通りです。
[
{
"_type": "block",
"_key": "a1b2c3",
"style": "normal",
"markDefs": [],
"children": [
{
"_type": "span",
"_key": "d4e5f6",
"text": "Here's an example of our pipeline config:",
"marks": []
}
]
},
{
"_type": "codeBlock",
"_key": "g7h8i9",
"language": "typescript",
"code": "export default defineConfig({ ... })"
}
]すべてのブロックには_typeと_keyがあります。標準テキストブロックは"block"を使用し、子スパン(太字、斜体、リンクなどのマークをサポート)を持ちます。カスタムブロック(codeBlock、chartBlock、table、inlineImageなど)は独自の_typeを使用し、構造化されたフィールドを持ちます。
なぜこれが重要なのでしょうか? HTMLはレンダリングフォーマットであり、保存フォーマットではないからです。データベースに<h2>Title</h2><p>Some <strong>text</strong></p>を保存した場合、Webレンダリングに閉じ込められてしまいます。モバイルアプリ、メールニュースレター、PDF、またはAIエージェントのコンテキストウィンドウのためにそれをクリーンに抽出することはできません。Portable Textはコンテンツとプレゼンテーションを分離します。Portable Text仕様はオープンソースであり、Sanityへのロックインではありません。
本番環境でのカスタムブロック
私たちのパイプラインはPythonスクリプト(scripts/md_to_portable_text.py)を使用してMarkdownをPortable Textに変換します。コンバーターは標準ブロックに加え、4つのカスタムタイプを処理します。
table:@sanity/tableプラグインスキーマを使用。行とセルは構造化データとして保存されます。codeBlock:言語とコードが別々のフィールドであり、レンダリング時にシンタックスハイライトを可能にします。chartBlock:チャートタイプ、タイトル、軸ラベル、シリーズ名、データポイントが構造化JSONとして保存されます。フロントエンドはChart.jsでこれらをレンダリングします。inlineImage:altテキスト、ソース、オプションのキャプションが別々のフィールドとして保存されます。
この構造により、ブログ内のすべてのコード例(*[body[]._type == "codeBlock"])をクエリしたり、チャートを含む投稿を見つけたり、altテキストが欠落しているすべての画像を抽出したりすることが、すべてGROQを通じて可能になります。
Portable Textのレンダリング
フロントエンドでは、@portabletext/react(またはSvelte/Vueの同等品)を使用します。各ブロックタイプのカスタムコンポーネントを登録します。
import { PortableText } from '@portabletext/react'
const components = {
types: {
codeBlock: ({ value }) => (
<pre className={`language-${value.language}`}>
<code>{value.code}</code>
</pre>
),
chartBlock: ({ value }) => <Chart data={value} />,
inlineImage: ({ value }) => (
<figure>
<img src={value.src} alt={value.alt} />
{value.caption && <figcaption>{value.caption}</figcaption>}
</figure>
),
},
}
// In your component:
<PortableText value={post.body} components={components} />これが完全なレンダリングパイプラインです。PortableTextコンポーネントは標準ブロック(段落、見出し、リスト、マーク)を自動的に処理します。カスタムタイプに対してのみカスタムコンポーネントを定義する必要があります。
Sanity CMSでの多言語コンテンツ
Sanityは、ドキュメントレベルのローカリゼーション(正規の参照でリンクされた言語ごとの別々のドキュメント)またはフィールドレベルのローカリゼーション(1つのドキュメント内の翻訳されたフィールド)を通じて多言語コンテンツをサポートします。ドキュメントレベルはSEO和大規模な公開に適しており、それが私たちの10言語パイプラインで使用している方法です。
ドキュメントレベル vs フィールドレベルのローカリゼーション
| 側面 | ドキュメントレベル | フィールドレベル |
|---|---|---|
| アプローチ | 言語ごとに別々のドキュメント | 1つのドキュメントにすべての翻訳 |
| SEO | 各ドキュメントに独自のURL/スラッグ | 単一URL、言語別ページの提供が困難 |
| クエリの複雑さ | シンプルなフィルター:language == "de" | ネストされたフィールドアクセス:title.de |
| コンテンツサイズ | 小さく焦点を絞ったドキュメント | すべての言語を含む1つの大きなドキュメント |
| 適している用途 | ブログ投稿、ページ、SEO主導のコンテンツ | 小さなUI文字列、ラベル、メタデータ |
| 私たちの結論 | すべてにこれを使用 | 共有UI文字列のみ |
私たちはドキュメントレベルのローカリゼーションを選択しました。各翻訳が独自のスラッグ、URL、メタデータを持つためです。Supabase vs Firebaseに関する投稿のトルコ語版は、URLパラメータのハックではなく、適切なトルコ語であるsupabase-firebase-karsilastirmaというスラッグを得ます。
10言語パイプラインアーキテクチャ
自動化されたパイプラインの仕組みは以下の通りです。英語で投稿を作成し、それを9つの追加言語(ドイツ語、フランス語、オランダ語、スペイン語、トルコ語、イタリア語、スウェーデン語、ノルウェー語、アラビア語)に翻訳します。各翻訳はMarkdown変換、Portable Text生成、Sanity API公開を経ていきます。
アーキテクチャは以下のようになります。
- 執筆:YAMLフロントマター付きの英語Markdown
- 翻訳:9言語へのAI翻訳(完全性と発音記号の確認済み)
- 変換:Pythonスクリプトが各
.mdファイルをPortable Text JSONに変換 - 公開:SanityへのAPI呼び出し:ドキュメント作成、画像アップロード、参照のパッチ適用
各ドキュメントにはlanguageフィールドと、英語のオリジナルを指すcanonicalPost参照があります。投稿とそのすべての翻訳を取得するためのGROQクエリは以下の通りです。
// Fetch a post and all its translations
*[_type == "post" && slug.current == "sanity-cms-guide" && language == "en"][0]{
title,
language,
"translations": *[
_type == "post" &&
canonicalPost._ref == ^._id
]{
title,
language,
"slug": slug.current
}
}スキーマ側は簡単で、サポートされている言語のenumを持つlanguageフィールドです。
defineField({
name: 'language',
title: 'Language',
type: 'string',
options: {
list: [
{ title: 'English', value: 'en' },
{ title: 'German', value: 'de' },
{ title: 'French', value: 'fr' },
{ title: 'Dutch', value: 'nl' },
{ title: 'Spanish', value: 'es' },
{ title: 'Turkish', value: 'tr' },
{ title: 'Italian', value: 'it' },
{ title: 'Swedish', value: 'sv' },
{ title: 'Norwegian', value: 'no' },
{ title: 'Arabic', value: 'ar' },
],
},
validation: (Rule) => Rule.required(),
})私たちが苦労して学んだ落とし穴の一つ:英語のドキュメントを最初に公開し、その後、翻訳のcanonicalPost参照を公開済みドキュメントIDを使用してパッチ適用します。drafts.プレフィックスではありません。Sanityは内部的に下書きと公開済みドキュメントを別々のエンティティとして扱います。
このパイプラインがModel Context Protocolにどのように接続されるかの詳細については、次のセクションを参照してください。
Sanity AI機能:MCP、Canvas、エージェントコンテキスト
Sanityは自身をAI時代のコンテンツオペレーティングシステムと位置付けています。主要なAI機能には、AIエージェントがコンテンツを読み書きするためのMCPサーバー、Studio内でのAI支援編集のためのCanvas、および構造化されたコンテンツをスキーマ認識でクエリするための本番用AIエージェント向けAgent Contextが含まれます。
MCPサーバー統合
Sanity MCPサーバーにより、Claude Code、Cursor、WindsurfなどのAIエージェントがプログラム的にSanityワークスペースと対話できます。エージェントはカスタムAPIラッパーなしで、スキーマの読み取り、GROQクエリの実行、ドキュメントの作成、コンテンツの管理を行うことができます。
私たちはコンテンツパイプラインで毎日Sanity MCPサーバーを使用しています。AIエージェントはスキーマをクエリしてドキュメント構造を理解し、内部リンクの機会を見つけるために既存の投稿を取得し、新しいドキュメントを公開します。MCPプロトコルはエージェントにスキーマ認識を提供し、どのフィールドが存在し、どのようなタイプを期待し、どのようなバリデーションルールが適用されるかを知っています。ビジネス向けAIエージェントのワークフローを構築している場合、これは強力なパターンです。
本番用AIのためのエージェントコンテキスト
エージェントコンテキストは、本番グレードのAI統合のための別の機能です。開発者ツール向けに設計されたMCPサーバーとは異なり、エージェントコンテキストは、実行時にコンテンツをクエリする必要があるAIエージェント(チャットボット、レコメンデーションエンジン、コンテンツパーソナライゼーションシステムなど)に対し、読み取り専用のスコープされたアクセスを提供します。
この違いは重要です。MCPはビルド時および編集ワークフロー(スキーマ認識開発ツール)用であり、エージェントコンテキストは適切な認証とレート制限を備えたランタイムコンテンツアクセス用です。
Sanityの構造化されたコンテンツはここで真の優位性をもたらします。WordPressサイトはコンテンツをHTMLの塊として保存するため、AIエージェントはコンテンツを理解するためにHTMLを解析する必要があります。Sanityは定義されたスキーマを持つ型付けされたJSONドキュメントを保存します。エージェントは*[_type == "product" && category == "electronics"]{name, price, features}をクエリし、クリーンで構造化されたデータを取得できます。スクレイピングも、解析も、推測も不要です。
TechsyでのSanityの活用方法
これは仮説的なセクションではありません。私たちは過去1年間に構築した自動化パイプラインを使用して、4つの本番ウェブサイトでSanity CMSを運用し、10言語で公開しています。以下がそのアーキテクチャです。
コンテンツパイプラインアーキテクチャ
パイプラインは研究から10言語すべてでの公開済み投稿に至ります。
- 研究:キーワード分析、競合ギャップの特定、SERPパターンの分析
- ブリーフ:セクションガイダンス、単語数、内部リンクを含む構造化された執筆仕様
- 執筆:YAMLフロントマター付きの英語Markdownを作成
- 変換:PythonスクリプトがMarkdownを5つのカスタムブロックタイプを持つPortable Text JSONに変換
- 公開:SanityへのAPI呼び出し:
createOrReplaceドキュメント、画像をSanity CDNにアップロード、著者/カテゴリ参照のパッチ適用 - 翻訳:9言語へのAI翻訳、完全性の確認
- 翻訳の公開:言語ごとに同じ変換/公開フロー、
canonicalPost参照を英語のオリジナルにパッチ適用
カスタムスキーマはblock、table、codeBlock、chartBlock、inlineImageタイプをサポートし、すべてがバリデーションルール付きの本番用Sanityスキーマオブジェクトとして定義されています。テストしたスタートアップ向けAIツールの中で、このSanityベースのパイプラインは大規模な構造化コンテンツにとって最も信頼性が高いものでした。
400以上の公開記事からの教訓
誰かが事前に教えてくれていればよかったと思うことがいくつかあります。
参照パッチの順序が重要です。 Sanityの参照は、まだ存在しないドキュメントを指すことはできません。英語の投稿を最初に公開し、その後、英語ドキュメントの公開済みIDを指すcanonicalPostを持つ翻訳を作成します。初期段階でこれを何度か壊してしまいました。
スキーマのデプロイはワークスペースごとです。 複数のSanityプロジェクトを実行している場合(私たちは4つ実行しています)、それぞれに個別にスキーマをデプロイする必要があります:プロジェクト設定ごとにnpx sanity@latest schema deploy。
無料枠は実在します。 4つのサイトのうち2つを数ヶ月間無料プランで運用しました。20ユーザー、月間500K APIリクエスト、100K CDNリクエスト。これはおもちゃのプロジェクトだけでなく、実際の本番サイトに十分な量です。
Portable Textの変換がボトルネックです。 MarkdownからPortable Textへの変換は単純ではありません。ネストされたリスト、ブロック引用内のテーブル、特殊文字を含むコードブロック、あらゆる所にエッジケースがあります。変換スクリプトは何ヶ月も改良を重ねてきました。
プロジェクト用にSanityのセットアップでお手伝いが必要ですか? 私たちは4つの本番サイト向けに多言語コンテンツパイプラインを構築しました。無料相談を受ける
Sanity CMS価格の内訳
Sanityは3つのプランを提供しています:Free(20ユーザー、月間500K APIリクエスト)、Growth(高度なロールとスケジュールされた下書き付きで$15/ユーザー/月)、Enterprise(SLAとコンプライアンス機能付きのカスタム価格)。無料枠はヘッドレスCMS市場で最も寛容なものです。
| 機能 | Free | Growth ($15/ユーザー/月) | Enterprise |
|---|---|---|---|
| ユーザー | 20 | 50 | 無制限 |
| APIリクエスト | 月間500K | 月間2.5M | カスタム |
| CDNリクエスト | 月間100K | 月間500K | カスタム |
| ロール | 管理者のみ | 管理者、開発者、エディタ、貢献者 | カスタムロール |
| コラボレーション | リアルタイム編集 | + スケジュール公開、下書き | + ワークフロー |
| サポート | コミュニティ | メール | 専任 + SLA |
| コンプライアンス | , | , | SOC 2, HIPAA |
無料枠では、制限に達することなく2つのサイトを運営しています。$15/ユーザー/月のGrowthプランは、ロールベースのアクセス(技術者以外のエディタが増えた際に重要)とスケジュール公開を追加しました。Growthではビューアーが無料であり、これは素晴らしい配慮です。ステークホルダーに読み取りアクセスを与えても罰則はありません。
競合他社と比較するとどうでしょうか?
| 機能 | Sanity Free | Contentful Free | Strapi Cloud Free | Payload Cloud |
|---|---|---|---|---|
| ユーザー | 20 | 1 | 1 | 1 |
| コンテンツタイプ | 無制限 | 48 | 無制限 | 無制限 |
| API呼び出し | 月間500K | 含まれる | 含まれる | 含まれる |
| カスタムタイプ | はい | 制限あり | はい | はい |
| 成長時の価格 | $15/ユーザー/月 | $300/月 | $29/月 | $50/月 |
Sanityの20ユーザー無料枠は例外的です。Contentfulは無料枠で1ユーザーに制限され、Teamプランでは月間$300に跳ね上がります。スタートアップ或小規模チームの場合、Sanityの無料プランにより、費用をかけずに実際の本番ワークロードを実行できます。
Sanityは、対象となるスタートアップに1年間の無料Growthアクセスを提供するスタートアッププログラムも提供しています。資格がある場合は申請する価値があります。
よくある質問
Sanity CMSとは何ですか? また、どのように動作しますか?
Sanity CMSは、Content Lakeと呼ばれる管理型バックエンドに構造化されたJSONドキュメントを保存するヘッドレスコンテンツプラットフォームです。Sanity Studio(カスタマイズ可能なReactアプリ)を通じてコンテンツを編集し、GROQまたはGraphQLでクエリを実行し、任意のフロントエンドフレームワークでレンダリングします。コンテンツはすべての接続されたクライアント間でリアルタイムに同期されます。
Sanity CMSは無料ですか?
はい。Sanityの無料枠には20ユーザー、月間500K APIリクエスト、100K CDNリクエストが含まれており、ヘッドレスCMSプラットフォームの中で最も寛容な無料プランです。Growthプランはユーザーあたり月間$15で、ロールベースのアクセス、スケジュール公開、およびより高い制限を追加します。Enterpriseの価格はカスタムです。
SanityとContentfulの違いは何ですか?
Sanityはスキーマアズコード(スキーマはコードベース内に存在)、クエリ用のGROQ、完全にカスタマイズ可能なオープンソースStudioを使用します。ContentfulはGUIベースのコンテンツモデリング、GraphQL、カスタマイズ性が低いホスト型エディタを使用します。Sanityの無料枠には20ユーザーが含まれますが、Contentfulは1ユーザーです。Contentfulにはより大きなプラグインマーケットプレイスがあります。
Sanity CMSは初心者に向いていますか?
Sanity Studioはコンテンツエディタにとって直感的であり、編集体験には技術的知識は必要ありません。ただし、スキーマのセットアップにはJavaScriptまたはTypeScriptの習熟が必要です。Sanityは優れたドキュメント、プロジェクトテンプレート、活発なサポートを持つコミュニティSlackを提供しています。npm create sanity@latestとブログテンプレートから始めてください。
Sanityをセルフホストできますか?
Sanity StudioはオープンソースのReactアプリケーションであるため、完全にセルフホスト可能です。Vercel、Netlify、または任意の静的ホスティングプロバイダーにデプロイできます。Content Lakeバックエンドは管理型サービスであり、データ層のセルフホスティングオプションはありません。これはトレードオフです:インフラストラクチャ管理はゼロですが、オンプレミスでのデータ制御はありません。
Sanityはどのような種類のデータベースを使用していますか?
SanityのContent Lakeは従来のSQLまたはNoSQLデータベースではありません。GROQクエリレイヤーを上に載せた構造化JSONとしてコンテンツを保存する管理型ドキュアストアです。基盤となるデータベースと直接対話することはなく、SanityのAPIを通じて対話します。ドキュメントには完全なバージョン履歴とリアルタイム同期が組み込まれています。
Sanity CMSはオープンソースですか?
Sanity StudioはMITライセンスの下でオープンソースであり、フォーク、カスタマイズ、セルフホストが可能です。Content Lakeバックエンドは独自SaaSです。GROQクエリ言語仕様もオープンソースであり、GitHubで公開されています。Portable Text仕様もオープンソースであり、portabletext.orgで維持されています。
SanityにおけるPortable Textとは何ですか?
Portable Textは、構造化されたリッチテキストのためのSanityの仕様です。コンテンツをHTML文字列として保存するのではなく、段落、見出し、画像、カスタムブロックを配列内の型付けされたJSONオブジェクトとして表現します。これにより、コンテンツはフレームワークやプラットフォーム間でポータブルになります。コードスニペット、チャート、テーブルなどのカスタムブロックタイプを、独自の構造化フィールドとともに定義できます。
GROQとは何ですか? また、GraphQLとどう違いますか?
GROQ(Graph-Relational Object Queries)はSanityのネイティブクエリ言語です。その構文*[filter]{projection}は、SanityデータにおいてGraphQLよりも簡潔であり、->演算子による結合と計算フィールドの組み込みサポートを備えています。GraphQLも、標準化されたツールを好むチームや、すでにApollo Clientを使用しているチームのために利用可能です。
Sanityは多言語コンテンツをどのように処理しますか?
Sanityは、ドキュメントレベルのローカリゼーション(正規の参照でリンクされた言語ごとの別々のドキュメント)とフィールドレベルのローカリゼーション(1つのドキュメント内の翻訳されたフィールド)をサポートします。各翻訳が独自のURLとメタデータを持つため、ドキュメントレベルはSEOに適しています。私たちは、自動化された翻訳および公開パイプラインを使用して10言語で公開するために、ドキュメントレベルのローカリゼーションを使用しています。