Sanity? デバロッパーファーストなヘッドレスCMS
日本語では記事も少なく、技術採用として候補に出てきづらいですが、Sanityは、開発者から特に高い評価を得ているプラットフォームです。今回は実際にSanityを使ってみた経験をもとに、なぜこのCMSが選ばれるのかを解説してみます。
Sanityとは
ヘッドレスCMSの詳しい説明は省略するとして、Sanityは構造化コンテンツプラットフォームです。ノルウェー発のサービスで、コンテンツをデータとして扱うことに特化しています。
Sanityの構成要素
Sanityは3つの主要な部分で構成されています。
Sanity Studioは管理画面にあたる部分で、Reactで構築されたオープンソースのアプリケーションです。完全にカスタマイズ可能で、プロジェクトのニーズに合わせて編集インターフェースを作り込めます。
Content Lakeはクラウド上のデータストレージで、すべてのコンテンツが構造化されて保存されます。バージョン管理やリアルタイム同期機能も含まれています。
GROQはSanity独自のクエリ言語です。GraphQLにも似つつ、記述が簡単になる(...
で全てのフィールドが取得できるなど)仕様も追加されています。
なぜ注目されているのか
Sanityが注目される理由は、開発者とコンテンツ作成者の両方にとって使いやすいことです。開発者はコードでスキーマを定義でき、コンテンツ作成者はドラッグ&ドロップでコンテンツブロックを組み合わせたり、リアルタイムプレビューを見ながら編集したりできます。
Sanityが支持される3つの理由
開発者満足度調査で第1位を獲得
NetlifyのJamstackコミュニティ調査において、Sanityは満足度第1位のCMSに選ばれています。2021年の調査では最高の満足度スコアを記録し、2022年と2023年も継続して高い評価を得ています。G2.comでもヘッドレスCMS部門で4年連続トップの座を獲得しています。
コードファーストで自由度が高い
SanityはスキーマをJavaScriptで自由に定義できるため、プロジェクトの要件に完全に合わせることができます。Webアプリを作成する感覚でコンテンツ重視のウェブサイトを作成でき、WordPressのようなテンプレート制約もありません。
ビジュアル編集機能が充実
Sanity Studioは単なる管理画面ではなく、開発者がReactを使って完全にカスタマイズできる編集環境で、コンテンツ管理者にとって使いやすいインターフェースを構築できます。
充実した無料プランの内容
Sanityの無料プランは他社と比較してかなり寛大です。以下のリソースが無料で利用できます(2025年6月時点):
・20シート(管理者・閲覧者ロール)まで対応
・月間10ギガバイトの帯域幅
・月間100,000回のAPIリクエスト
・月間500,000回のCDNリクエスト
・プロジェクト数は無制限
小規模から中規模のプロジェクトであれば、無料プランだけで十分に運用できます。
注記: 具体的な制限値は変更される可能性があるため、最新の情報は公式サイトでご確認ください。
Next.jsでのセットアップ手順
実際にNext.jsプロジェクトでSanityを導入してみる例です。
# Sanityプロジェクトの作成
npm create sanity@latest
# Next.jsにSanityクライアントを追加
npm install @sanity/client next-sanity
スキーマの定義は直感的。
// schemas/post.js
export default {
name: 'post',
title: 'ブログ記事',
type: 'document',
fields: [
{
name: 'title',
title: 'タイトル',
type: 'string'
},
{
name: 'content',
title: '本文',
type: 'array',
of: [{type: 'block'}]
}
]
}
// sanity.config.js
import { defineConfig } from 'sanity'
import { deskTool } from 'sanity/desk'
import { schemaTypes } from './schemas'
export default defineConfig({
projectId: 'your-project-id',
dataset: 'production',
plugins: [deskTool()],
schema: {
types: schemaTypes,
},
})
設定ファイルを作成して、npm sanity dev
を走らせると、スキーマが登録され、管理画面が自動生成されます。
注目すべき機能
Server Componentsとの相性
Server Componentsと組み合わせると、開発がよりシンプルになります。next-sanityのsanityFetch関数は自動的にキャッシュタグを設定し、効率的なデータ取得を実現します。
// app/blog/page.js
import { sanityFetch } from '@/sanity/lib/live'
export default async function BlogPage() {
const { data: posts } = await sanityFetch({
query: `*[_type == "post"] {
title,
slug,
_createdAt
}`
})
return (
<div>
{posts.map(post => (
<article key={post.slug.current}>
<h2>{post.title}</h2>
</article>
))}
</div>
)
}
サーバーサイドで直接データを取得できるため、ローディング状態の管理が不要になります。
Live機能でリアルタイム更新とISRの完全自動化
キラーフューチャーとなる部分で、next-sanity/live
を使うとリアルタイム更新が可能になり、さらにISR(Incremental Static Regeneration)が完全自動化されます。これはNext.js 15のServer Functionsと連携するとかなり革新的な仕組みです。
以下の手順でLive機能を設定できます:
// 1. sanity/lib/live.ts - Live機能の設定
import { defineLive } from 'next-sanity'
import { client } from './client'
const token = process.env.SANITY_API_READ_TOKEN
if (!token) {
throw new Error('Missing SANITY_API_READ_TOKEN')
}
export const { sanityFetch, SanityLive } = defineLive({
client,
serverToken: token,
browserToken: token,
})
// 2. app/layout.js - レイアウトにSanityLiveコンポーネントを追加
import { VisualEditing } from 'next-sanity'
import { SanityLive } from '@/sanity/lib/live'
import { draftMode } from 'next/headers'
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<SanityLive />
{(await draftMode()).isEnabled && <VisualEditing />}
</body>
</html>
)
}
// 3. app/blog/page.js - データフェッチでsanityFetchを使用
import { sanityFetch } from '@/sanity/lib/live'
export default async function BlogPage() {
const { data: posts } = await sanityFetch({
query: `*[_type == "post"] {
title,
slug,
_createdAt
}`
})
return (
<div>
{posts.map(post => (
<article key={post.slug.current}>
<h2>{post.title}</h2>
</article>
))}
</div>
)
}
自動化の仕組み
SanityLive
コンポーネントは以下の仕組みで自動更新を実現します:
-
自動タグ設定:
sanityFetch
がキャッシュタグを自動生成 - リアルタイム監視: Live Content APIでコンテンツ変更を監視
-
自動更新: コンテンツ変更時にServer Functionが
revalidateTag()
を実行 - グローバル反映: 一人のユーザーがアクセスするだけで、全ユーザー向けにキャッシュが更新
パフォーマンス最適化
コスト効率
- API使用量が予測可能で、Content Lakeへの無駄なリクエストを削減
- 必要な部分のみの精密な再生成で、ビルド時間を大幅短縮
高速更新
- 3つのクエリを使用するページで1つだけが変更された場合、その1つのみが再取得される
- キャッシュの無効化は次回アクセス時に発生するため、サーバー負荷を分散
シンプルな設定
- 複雑な設定は一切不要で、コンポーネントを追加するだけ
- エラーが起きやすい手動設定を完全に排除
リアルタイム更新
- コンテンツ変更時の完全自動更新(手動デプロイ不要)
- 静的ページの高速配信を維持しながらリアルタイム更新を実現
Sanity Studioでブログ記事のタイトルを編集すると、サイトを見ている全ユーザーに即座に反映されます。従来のJAMスタックのように「編集→保存→ビルド→デプロイ→確認」という手順は一切不要です。
GROQDによる型安全なクエリ構築
直接GROQを書く代わりに、GROQDというクエリビルダーライブラリを使う選択肢もあります。Nearform(旧Formidable)が開発したこのライブラリは、Zodを使ってランタイム型検証を提供します。
import { q } from 'groqd'
const { query, schema } = q('*')
.filterByType('post')
.grab({
title: q.string(),
slug: q('slug.current').string(),
publishedAt: q('_createdAt').string()
})
// 型安全なデータ取得
const posts = schema.parse(await client.fetch(query))
GROQDの利点は、クエリビルダーでGROQを構築しながら、同時にZodスキーマも生成することです。これにより、ランタイムでのデータ検証と静的型チェックの両方が実現されます。
従来のGROQでは返されるデータがany
型になってしまいますが、GROQDを使うことで具体的な型が推論され、開発時のエラーを大幅に減らせます。
良いことばかりではない部分
もちろん、Sanityにも改善の余地がある点があります。
独自技術の学習コスト
GROQ(Graph-Relational Object Queries)という独自のクエリ言語を覚える必要があります。SQLやGraphQLに慣れていても、GROQは別の文法を持つため習得に時間がかかります。
日本語ドキュメントの不足
公式ドキュメントは英語がメインで、日本語の情報が限られています。チュートリアルやトラブルシューティングを調べる際に英語を読む必要があり、開発効率に影響することがあります。
Portable Textの特殊性
Sanityは独自のPortable Text形式を採用しており、従来のHTMLやMarkdownとは異なるアプローチを取ります。これには以下のような特徴があります:
メリット:
- 構造化されたデータとして扱えるため、様々な出力形式に対応可能
- XSS攻撃のリスクが大幅に軽減
- 型安全性の向上とコンポーネントベースの柔軟な表示
制約:
- HTMLの直接編集ができない
- 他のCMSからの移行時にデータ変換が必要
- 慣れるまで独特の構造理解が必要
ただし、Sanity Block Toolsを使用すれば、既存のHTMLコンテンツをPortable Textに変換することは可能です。
番外編:Convexとの比較
Convexは全く違うユースケース(Backend-as-a-Service)ですが、似たアプローチを取るプラットフォームです。比較してみると興味深い点があります。
共通点:開発者ファーストな体験
どちらもコードファーストなアプローチを取っており、エンドツーエンドの型安全性を提供します。
// Sanity - コンテンツスキーマ
export default {
name: 'post',
type: 'document',
fields: [
{ name: 'title', type: 'string' }
]
}
// Convex - データベーススキーマ
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
export default defineSchema({
posts: defineTable({
title: v.string(),
})
});
両方ともTypeScriptでスキーマを定義し、フロントエンドまで完全な型推論が効きます。これにより開発時のエラーを大幅に減らせます。
デプロイメントの自動化
どちらもコード変更を検知して自動的にデプロイされる仕組みを持っています。
Sanityではnpx sanity deploy
でStudioがクラウドにデプロイされ、スキーマ変更はnpx sanity dev
で自動的に同期されます。
Convexではnpx convex dev
でリアルタイムにバックエンドコードが同期され、npx convex deploy
で本番環境にデプロイできます。
型生成とコード補完
両者とも自動的にTypeScript型を生成し、IDEでの開発体験を向上させます。
Sanityはsanity-typegen
で型を生成し、ConvexはAPIクライアント用の型を_generated
フォルダに自動生成します。どちらも変更時に自動更新されるため、常に最新の型情報でコーディングできます。
なぜ似たアプローチを取るのか
この2つのプラットフォームが似たアプローチを取る背景には、現代のフロントエンド開発の標準化があります。
Server Componentsによるパラダイムシフトにより、従来のクライアント・サーバー境界が曖昧になりました。データフェッチがサーバーサイドで行われるようになり、SanityのLive APIやConvexのリアクティブクエリのような、サーバーとクライアントをシームレスに繋ぐテックスタックが求められるようになっています。
コロケーション(Colocation)の標準化で、Next.jsのApp Routerでは、ルーティング、データフェッチ、UIコンポーネントが同一ディレクトリに配置されます。SanityもConvexも、スキーマ定義、クエリ、型生成を単一のファイルシステムで管理でき、関連するコードを近くに配置する設計思想を採用しています。
tRPCのようなライブラリが示したエンドツーエンド型安全性が浸透しつつあります。API境界を意識せずに関数呼び出しのような体験を提供することで、バックエンドからフロントエンドまで一貫した型推論が可能になります。両プラットフォームとも自動型生成により、この体験を実現しています。
主要CMSとの比較
CMS | 無料プラン | 有料プラン開始価格 | ビジュアル編集 | Next.js対応 |
---|---|---|---|---|
Sanity | 20シート、10GB帯域幅 | 15ドル/シート | ○ | ◎ |
MicroCMS | Hobbyプラン(2025年6月〜) | 要確認* | × | ○ |
Contentful | 10ユーザー、1スペース | 要確認* | △ | ○ |
Storyblok | 14日間無料トライアル | 要確認* | ◎ | ○ |
*価格は変動が激しいため、最新情報は各社公式サイトをご確認ください。
MicroCMSとの比較
MicroCMSは日本製で使いやすく、Hobbyプランはスキーマ種別が5までと制限が大きめ。日本語サポートが充実している点は大きなメリットです。
Contentfulとの比較
Contentfulは長い実績を持つ老舗ヘッドレスCMSですが、エンタープライズ向けの印象が強く、小規模プロジェクトには価格面でハードルが高い場合があります。
Storyblokとの比較
Storyblokは強力なビジュアル編集機能を持ちますが、Sanityの方がコードファーストで開発者フレンドリーな印象があります。
まとめ
Sanityを使ってみて感じたのは、「開発者のことを本当に考えて作られたCMS」ということです。無料プランが充実しており、Next.jsとの相性も抜群です。
確かに学習コストはありますが、一度慣れてしまえば他のCMSには戻れない予感です。
独自の概念やPortable Textの仕組みも、最初は戸惑うかもしれませんが、使えば使うほどその価値が見えてきます。
小さなプロジェクトから始めて、必要に応じてスケールアップできるのもSanityの魅力です。まずは無料プランで触ってみることをおすすめします。
参考リンク
・Sanity公式サイト
・Sanity Pricing
・Next.js公式ドキュメント
・G2 Reviews - Sanity
・Netlify Community Survey
・GROQD Documentation
注記: 最新の情報は各サービスの公式サイトでご確認ください。
Discussion