tinacms について
コンテンツ中心の Web アプリに TinaCMS を組み込むための実践的なスキルです。複数のフレームワークでの設定、スキーマ設計、トラブルシューティングを扱い、Git 管理とビジュアル編集を使うサイトの開発者向けです。
主な機能
- 01フレームワーク別の設定ガイド
- 02スキーマとコレクションの設計
- 03ビジュアル編集の連携
- 04設定とエラーのトラブル対応
活用シーン
- 01Next.js サイトへの CMS 導入
- 02ブログやドキュメントのコンテンツ設計
- 03編集者向けライブプレビューの有効化
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jackspace/ claudeskillz --skill tinacmsインストール後、Claude Code で/tinacmsを入力して読み込まれたか確認します。
同梱ファイルREADME.mdSKILL.json
詳細
TinaCMS スキル
モダンなウェブアプリケーションに TinaCMS を統合するための完全なスキルです。
TinaCMS とは?
TinaCMS は、開発者とコンテンツ制作者がコンテンツ中心のウェブサイトでスムーズに共同作業できる、オープンソースの Git ベースのヘッドレスコンテンツ管理システム(CMS)です。
主な機能
-
Git ベースのストレージ
- Git リポジトリ内に Markdown、MDX、または JSON ファイルとしてコンテンツを保存します
- 完全なバージョン管理と変更履歴を利用できます
- ベンダーロックインがなく、コンテンツはリポジトリ内に保存されます
-
ビジュアル/コンテキスト編集
- 横並びの編集エクスペリエンス
- 入力中に変更をライブプレビューできます
- Markdown コンテンツを WYSIWYG のように編集できます
-
スキーマ駆動のコンテンツモデリング
- コード内でコンテンツ構造を定義します(
tina/config.ts) - スキーマから型安全な GraphQL API が自動生成されます
- コンテンツを整理するためのコレクションとフィールドのシステム
- コード内でコンテンツ構造を定義します(
-
柔軟なデプロイ
- TinaCloud:マネージドサービス(最も簡単で、無料プランも利用できます)
- セルフホスト:Cloudflare Workers、Vercel Functions、Netlify Functions、AWS Lambda
- 複数の認証オプション(Auth.js、カスタム、ローカル開発)
-
フレームワークのサポート
- 最適:Next.js(App Router と Pages Router)
- 良好:React、Astro(ビジュアル編集は実験的)、Gatsby、Hugo、Jekyll、Remix、11ty
- フレームワーク非依存:あらゆるフレームワークで動作します(ビジュアル編集は React に限定)
現在のバージョン
- tinacms:2.9.0(2025年9月)
- @tinacms/cli:1.11.0(2025年10月)
- React のサポート:19.x(>=18.3.1 <20.0.0)
このスキルを使う場面
✅ TinaCMS を使う場合:
-
コンテンツ中心のサイトを構築する
- ブログや個人ウェブサイト
- ドキュメントサイト
- マーケティングウェブサイト
- ポートフォリオサイト
-
技術に詳しくない編集者にもアクセスが必要
- コーディングの知識がないコンテンツチーム
- ページを管理するマーケティングチーム
- ブログ記事を執筆する著者
-
Git ベースのワークフローを希望する
- Git でコンテンツをバージョン管理したい
- プルリクエストでコンテンツをレビューする必要がある
- コードとともにリポジトリ内でコンテンツを管理したい
-
ビジュアル編集が必要
- 編集者が変更をライブで確認したい
- WYSIWYG のエクスペリエンスが望ましい
- 横並びの編集ワークフローを使いたい
❌ TinaCMS を使わない場合:
-
リアルタイムの共同作業が必要
- 複数のユーザーが同時に編集する場合(Google ドキュメントのような形式)
- 代わりに Sanity、Contentful、または Firebase を使ってください
-
動的なデータが多い
- 在庫が頻繁に変動する E コマースの商品カタログ
- リアルタイムのダッシュボード
- 代わりに従来型のデータベース(D1、PostgreSQL)を使ってください
-
コンテンツ管理が不要
- アプリケーションがコンテンツ駆動ではなく、データ駆動である
- ハードコードされたコンテンツで十分である
フレームワーク別のセットアップパターン
使用するフレームワークに応じたセットアップパターンを使ってください。
1. Next.js のセットアップ(推奨)
App Router(Next.js 13 以降)
手順:
-
TinaCMS を初期化します:
npx @tinacms/cli@latest init- 公開アセットディレクトリを尋ねられたら、
publicと入力します
- 公開アセットディレクトリを尋ねられたら、
-
package.json のスクリプトを更新します:
{ "scripts": { "dev": "tinacms dev -c \"next dev\"", "build": "tinacms build && next build", "start": "tinacms build && next start" } } -
環境変数を設定します:
# .env.local NEXT_PUBLIC_TINA_CLIENT_ID=your_client_id TINA_TOKEN=your_read_only_token -
開発サーバーを起動します:
npm run dev -
管理インターフェースにアクセスします:
http://localhost:3000/admin/index.html
作成される主なファイル:
tina/config.ts- スキーマ設定app/admin/[[...index]]/page.tsx- 管理 UI のルート(App Router を使う場合)
テンプレート:templates/nextjs/tina-config-app-router.ts を参照してください
Pages Router(Next.js 12 以前)
セットアップは同じですが、管理ルートは次のようになります:
- app ディレクトリの代わりに
pages/admin/[[...index]].tsx
データ取得パターン:
// pages/posts/[slug].tsx
import { client } from '../../tina/__generated__/client'
import { useTina } from 'tinacms/dist/react'
export default function BlogPost(props) {
// Hydrate for visual editing
const { data } = useTina({
query: props.query,
variables: props.variables,
data: props.data
})
return (
<article>
<h1>{data.post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: data.post.body }} />
</article>
)
}
export async function getStaticProps({ params }) {
const response = await client.queries.post({
relativePath: `${params.slug}.md`
})
return {
props: {
data: response.data,
query: response.query,
variables: response.variables
}
}
}
export async function getStaticPaths() {
const response = await client.queries.postConnection()
const paths = response.data.postConnection.edges.map((edge) => ({
params: { slug: edge.node._sys.filename }
}))
return { paths, fallback: 'blocking' }
}
テンプレート:templates/nextjs/tina-config-pages-router.ts を参照してください
2. Vite + React のセットアップ
手順:
-
依存関係をインストールします:
npm install react@^19 react-dom@^19 tinacms -
TinaCMS を初期化します:
npx @tinacms/cli@latest init- 公開アセットのディレクトリを
publicに設定します
- 公開アセットのディレクトリを
-
vite.config.ts を更新します:
import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], server: { port: 3000 // TinaCMS default } }) -
package.json のスクリプトを更新します:
{ "scripts": { "dev": "tinacms dev -c \"vite\"", "build": "tinacms build && vite build", "preview": "vite preview" } } -
管理インターフェースを作成します:
オプション A:手動ルート(React Router)
// src/pages/Admin.tsx import TinaCMS from 'tinacms' export default function Admin() { return <div id="tina-admin" /> }オプション B:直接 HTML
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Tina CMS</title> <meta name="viewport" content="width=device-width, initial-scale=1" /> </head> <body> <div id="root"></div> <script type="module" src="/@fs/[path-to-tina-admin]"></script> </body> </html> -
ビジュアル編集には useTina フックを使用します:
import { useTina } from 'tinacms/dist/react' import { client } from '../tina/__generated__/client' function BlogPost({ initialData }) { const { data } = useTina({ query: initialData.query, variables: initialData.variables, data: initialData.data }) return ( <article> <h1>{data.post.title}</h1> <div>{/* render body */}</div> </article> ) } -
環境変数を設定します:
# .env VITE_TINA_CLIENT_ID=your_client_id VITE_TINA_TOKEN=your_read_only_token
テンプレート:templates/vite-react/ を参照してください。
3. Astro のセットアップ
手順:
-
公式スターターを使用します(推奨):
npx create-tina-app@latest --template tina-astro-starterまたは、手動で初期化します:
npx @tinacms/cli@latest init -
package.json のスクリプトを更新します:
{ "scripts": { "dev": "tinacms dev -c \"astro dev\"", "build": "tinacms build && astro build", "preview": "astro preview" } } -
Astro を設定します:
// astro.config.mjs import { defineConfig } from 'astro/config' import react from '@astro/react' export default defineConfig({ integrations: [react()] // Required for Tina admin }) -
ビジュアル編集(実験的機能):
- React コンポーネントが必要です
- インタラクティブな編集には
client:tinaDirectiveを使用します - 2025 年 10 月時点では、完全なビジュアル編集は実験的機能です
-
環境変数を設定します:
# .env PUBLIC_TINA_CLIENT_ID=your_client_id TINA_TOKEN=your_read_only_token
最適な用途:コンテンツ中心の静的サイト、ドキュメント、ブログ
テンプレート:templates/astro/ を参照してください。
4. フレームワークに依存しないセットアップ
対象:Hugo、Jekyll、Eleventy、Gatsby、Remix、または任意のフレームワーク
手順:
-
TinaCMS を初期化します:
npx @tinacms/cli@latest init -
ビルドスクリプトを手動で設定します:
{ "scripts": { "dev": "tinacms dev -c \"<your-dev-command>\"", "build": "tinacms build && <your-build-command>" } } -
管理インターフェース:
http://localhost:<port>/admin/index.htmlに自動的に作成されます- ポートは使用するフレームワークによって異なります
-
データの取得:
- ビジュアル編集は利用できません(サイドバーのみ)
- Git と連携したインターフェースからコンテンツを編集します
- 変更はファイルに直接保存されます
-
環境変数を設定します:
TINA_CLIENT_ID=your_client_id TINA_TOKEN=your_read_only_token
制限事項:
- ビジュアル編集は利用できません(React のみの機能)
- 手動での統合が必要です
- サイドバーでの編集のみ利用できます
スキーマモデリングのベストプラクティス
コンテンツ構造は tina/config.ts で定義します。
基本的な設定構造
import { defineConfig } from 'tinacms'
export default defineConfig({
// Branch configuration
branch: process.env.GITHUB_BRANCH ||
process.env.VERCEL_GIT_COMMIT_REF ||
'main',
// TinaCloud credentials (if using managed service)
clientId: process.env.NEXT_PUBLIC_TINA_CLIENT_ID,
token: process.env.TINA_TOKEN,
// Build configuration
build: {
outputFolder: 'admin',
publicFolder: 'public',
},
// Media configuration
media: {
tina: {
mediaRoot: '',
publicFolder: 'public',
},
},
// Content schema
schema: {
collections: [
// Define collections here
],
},
})
コレクション
コレクション = コンテンツタイプ+ディレクトリのマッピング
{
name: 'post', // Singular, internal name (used in API)
label: 'Blog Posts', // Plural, display name (shown in admin)
path: 'content/posts', // Directory where files are stored
format: 'mdx', // File format: md, mdx, markdown, json, yaml, toml
fields: [/* ... */] // Array of field definitions
}
主なプロパティ:
name:内部識別子(英数字とアンダースコアのみ)label:管理インターフェースに表示する名前path:プロジェクトルートからの相対ファイルパスformat:ファイル拡張子(既定値は 'md')fields:コンテンツ構造の定義
フィールドタイプのリファレンス
| タイプ | 用途 | 例 |
|---|---|---|
string | 短いテキスト(1 行) | タイトル、スラッグ、著者名 |
rich-text | 書式付きの長いコンテンツ | ブログ本文、ページコンテンツ |
number | 数値 | 価格、数量、評価 |
datetime | 日付/時刻 | 公開日、イベント時刻 |
boolean | 真偽値の切り替え | 下書きステータス、注目フラグ |
image | 画像のアップロード | ヒーロー画像、サムネイル、アバター |
reference | 別のドキュメントへのリンク | 著者、カテゴリ、関連投稿 |
object | 入れ子になったフィールドのグループ | SEO メタデータ、ソーシャルリンク |
完全なリファレンス:references/field-types-reference.md を参照してください。
コレクションのテンプレート
ブログ投稿コレクション
{
name: 'post',
label: 'Blog Posts',
path: 'content/posts',
format: 'mdx',
fields: [
{
type: 'string',
name: 'title',
label: 'Title',
isTitle: true, // Shows in content list
required: true
},
{
type: 'string',
name: 'excerpt',
label: 'Excerpt',
ui: {
component: 'textarea' // Multi-line input
}
},
{
type: 'image',
name: 'coverImage',
label: 'Cover Image'
},
{
type: 'datetime',
name: 'date',
label: 'Published Date',
required: true
},
{
type: 'reference',
name: 'author',
label: 'Author',
collections: ['author'] // References author collection
},
{
type: 'boolean',
name: 'draft',
label: 'Draft',
description: 'If checked, post will not be published',
required: true
},
{
type: 'rich-text',
name: 'body',
label: 'Body',
isBody: true // Main content area
}
],
ui: {
router: ({ document }) => `/blog/${document._sys.filename}`
}
}
テンプレート:templates/collections/blog-post.ts を参照してください。
ドキュメントページコレクション
{
name: 'doc',
label: 'Documentation',
path: 'content/docs',
format: 'mdx',
fields: [
{
type: 'string',
name: 'title',
label: 'Title',
isTitle: true,
required: true
},
{
type: 'string',
name: 'description',
label: 'Description',
ui: {
component: 'textarea'
}
},
{
type: 'number',
name: 'order',
label: 'Order',
description: 'Sort order in sidebar'
},
{
type: 'rich-text',
name: 'body',
label: 'Body',
isBody: true,
templates: [
// MDX components can be defined here
]
}
],
ui: {
router: ({ document }) => {
const breadcrumbs = document._sys.breadcrumbs.join('/')
return `/docs/${breadcrumbs}`
}
}
}
テンプレート:templates/collections/doc-page.ts を参照してください。
著者コレクション(参照先)
{
name: 'author',
label: 'Authors',
path: 'content/authors',
format: 'json', // Use JSON for structured data
fields: [
{
type: 'string',
name: 'name',
label: 'Name',
isTitle: true,
required: true
},
{
type: 'string',
name: 'email',
label: 'Email',
ui: {
validate: (value) => {
if (!value?.includes('@')) {
return 'Invalid email address'
}
}
}
},
{
type: 'image',
name: 'avatar',
label: 'Avatar'
},
{
type: 'string',
name: 'bio',
label: 'Bio',
ui: {
component: 'textarea'
}
},
{
type: 'object',
name: 'social',
label: 'Social Links',
fields: [
{
type: 'string',
name: 'twitter',
label: 'Twitter'
},
{
type: 'string',
name: 'github',
label: 'GitHub'
}
]
}
]
}
テンプレート:templates/collections/author.ts を参照してください。
ランディングページコレクション(複数のテンプレート)
{
name: 'page',
label: 'Pages',
path: 'content/pages',
format: 'mdx',
templates: [ // Multiple templates for different page types
{
name: 'basic',
label: 'Basic Page',
fields: [
{
type: 'string',
name: 'title',
label: 'Title',
isTitle: true,
required: true
},
{
type: 'rich-text',
name: 'body',
label: 'Body',
isBody: true
}
]
},
{
name: 'landing',
label: 'Landing Page',
fields: [
{
type: 'string',
name: 'title',
label: 'Title',
isTitle: true,
required: true
},
{
type: 'object',
name: 'hero',
label: 'Hero Section',
fields: [
{
type: 'string',
name: 'headline',
label: 'Headline'
},
{
type: 'string',
name: 'subheadline',
label: 'Subheadline',
ui: { component: 'textarea' }
},
{
type: 'image',
name: 'image',
label: 'Hero Image'
}
]
},
{
type: 'object',
name: 'cta',
label: 'Call to Action',
fields: [
{
type: 'string',
name: 'text',
label: 'Button Text'
},
{
type: 'string',
name: 'url',
label: 'Button URL'
}
]
}
]
}
]
}
テンプレートを使用する場合:ドキュメントの frontmatter に _template フィールドを含める必要があります:
---
_template: landing
title: My Landing Page
---
テンプレート:templates/collections/landing-page.ts を参照してください。
よくあるエラーと解決策
1. ❌ ESbuild のコンパイルエラー
エラーメッセージ:
ERROR: Schema Not Successfully Built
ERROR: Config Not Successfully Executed
原因:
- カスタムローダー(webpack、babel プラグイン、esbuild ローダー)を使用するコードのインポート
- フロントエンド専用コード(
window、DOM API、React フックを使用)のインポート - 特定のモジュールではなく、コンポーネントライブラリ全体をインポート
解決方法:
必要なものだけをインポートしてください:
// ❌ Bad - Imports entire component directory
import { HeroComponent } from '../components/'
// ✅ Good - Import specific file
import { HeroComponent } from '../components/blocks/hero'
予防のヒント:
tina/config.tsのインポートは最小限にしてください- 型定義とシンプルなユーティリティのみをインポートしてください
- UI コンポーネントを直接インポートしないでください
- 必要に応じて、個別の
.schema.tsファイルを作成してください
参考:references/common-errors.md#esbuild を参照してください
2. ❌ モジュール解決:「Could not resolve 'tinacms'」
エラーメッセージ:
Error: Could not resolve "tinacms"
原因:
- インストールが破損している、または不完全
- 依存関係間のバージョン不一致
- ピア依存関係が不足している
解決方法:
# Clear cache and reinstall
rm -rf node_modules package-lock.json
npm install
# Or with pnpm
rm -rf node_modules pnpm-lock.yaml
pnpm install
# Or with yarn
rm -rf node_modules yarn.lock
yarn install
予防策:
- ロックファイル(
package-lock.json、pnpm-lock.yaml、yarn.lock)を使用してください --no-optionalや--omit=optionalフラグを使用しないでください- React 以外のフレームワークでも、
reactとreact-domがインストールされていることを確認してください
3. ❌ フィールド名の制約
エラーメッセージ:
Field name contains invalid characters
原因:
- TinaCMS のフィールド名に使用できるのは、英字、数字、アンダースコアのみです
- ハイフン、スペース、特殊文字は使用できません
解決方法:
// ❌ Bad - Uses hyphens
{
name: 'hero-image',
label: 'Hero Image',
type: 'image'
}
// ❌ Bad - Uses spaces
{
name: 'hero image',
label: 'Hero Image',
type: 'image'
}
// ✅ Good - Uses underscores
{
name: 'hero_image',
label: 'Hero Image',
type: 'image'
}
// ✅ Good - CamelCase also works
{
name: 'heroImage',
label: 'Hero Image',
type: 'image'
}
注:これは Forestry.io からの移行における破壊的変更です
4. ❌ Docker のバインドに関する問題
エラー:
- Docker コンテナの外部から TinaCMS 管理画面にアクセスできない
原因:
- TinaCMS はデフォルトで
127.0.0.1(localhost のみ)にバインドされます - Docker コンテナが外部接続を受け入れるには、
0.0.0.0へのバインドが必要です
解決方法:
# Ensure framework dev server listens on all interfaces
tinacms dev -c "next dev --hostname 0.0.0.0"
tinacms dev -c "vite --host 0.0.0.0"
tinacms dev -c "astro dev --host 0.0.0.0"
Docker Compose の例:
services:
app:
build: .
ports:
- "3000:3000"
command: npm run dev # Which runs: tinacms dev -c "next dev --hostname 0.0.0.0"
5. ❌ _template キーがないエラー
エラーメッセージ:
GetCollection failed: Unable to fetch
template name was not provided
原因:
- コレクションが
templates配列(複数のスキーマ)を使用している - ドキュメントのフロントマターに
_templateフィールドがない templatesからfieldsへの移行時に、ドキュメントが更新されていない
解決方法:
オプション 1:代わりに fields を使用する(単一テンプレートの場合に推奨)
{
name: 'post',
path: 'content/posts',
fields: [/* ... */] // No _template needed
}
オプション 2:フロントマターに _template があることを確認する
---
_template: article # ← Required when using templates array
title: My Post
---
移行スクリプト(templates から fields に変換する場合):
# Remove _template from all files in content/posts/
find content/posts -name "*.md" -exec sed -i '/_template:/d' {} +
6. ❌ パスの不一致に関する問題
エラー:
- Tina 管理画面にファイルが表示されない
- 保存時に「File not found」エラーが発生する
- GraphQL クエリの結果が空になる
原因:
- コレクション設定の
pathが実際のファイルディレクトリと一致していない - 相対パスと絶対パスの混同
- 末尾のスラッシュに関する問題
解決方法:
// Files located at: content/posts/hello.md
// ✅ Correct
{
name: 'post',
path: 'content/posts', // Matches file location
fields: [/* ... */]
}
// ❌ Wrong - Missing 'content/'
{
name: 'post',
path: 'posts', // Files won't be found
fields: [/* ... */]
}
// ❌ Wrong - Trailing slash
{
name: 'post',
path: 'content/posts/', // May cause issues
fields: [/* ... */]
}
デバッグ:
npx @tinacms/cli@latest auditを実行してパスを確認します- 指定されたディレクトリにファイルがあることを確認します
- ファイル拡張子が
formatフィールドと一致していることを確認します
7. ❌ ビルドスクリプトの実行順序に関する問題
エラーメッセージ:
ERROR: Cannot find module '../tina/__generated__/client'
ERROR: Property 'queries' does not exist on type '{}'
原因:
tinacms buildより先にフレームワークのビルドが実行されている- TypeScript のコンパイル前に Tina の型が生成されていない
- CI/CD パイプラインの順序が正しくない
解決方法:
{
"scripts": {
"build": "tinacms build && next build" // ✅ Tina FIRST
// NOT: "build": "next build && tinacms build" // ❌ Wrong order
}
}
CI/CD の例(GitHub Actions):
- name: Build
run: |
npx @tinacms/cli@latest build # Generate types first
npm run build # Then build framework
重要な理由:
tinacms buildはtina/__generated__/に TypeScript の型を生成します- フレームワークのビルドを正常に行うには、これらの型が必要です
- 順序を誤ると型エラーが発生します
8. ❌ TinaCMS アセットの読み込み失敗
エラーメッセージ:
Failed to load resource: net::ERR_CONNECTION_REFUSED
http://localhost:4001/...
原因:
- 開発用の
admin/index.htmlを本番環境にプッシュした(localhost からアセットを読み込む) - サイトがサブディレクトリで配信されているのに、
basePathが設定されていない
解決方法:
本番環境へのデプロイの場合:
{
"scripts": {
"build": "tinacms build && next build" // ✅ Always build
// NOT: "build": "tinacms dev" // ❌ Never dev in production
}
}
サブディレクトリへのデプロイの場合:
// tina/config.ts
export default defineConfig({
build: {
outputFolder: 'admin',
publicFolder: 'public',
basePath: 'your-subdirectory' // ← Set if site not at domain root
}
})
CI/CD の修正:
# GitHub Actions / Vercel / Netlify
- run: npx @tinacms/cli@latest build # Always use build, not dev
9. ❌ Reference Field 503 Service Unavailable
エラー:
- Reference Field のドロップダウンがタイムアウトし、503 エラーが発生します
- Reference Field の読み込み中に管理インターフェースが応答しなくなります
原因:
- 参照先のコレクションに項目が多すぎます(数百〜数千件)
- 現在、Reference Field はページネーションに対応していません
解決策:
オプション 1:コレクションを分割する
// Instead of one huge "authors" collection
// Split by active status or alphabetically
{
name: 'active_author',
label: 'Active Authors',
path: 'content/authors/active',
fields: [/* ... */]
}
{
name: 'archived_author',
label: 'Archived Authors',
path: 'content/authors/archived',
fields: [/* ... */]
}
オプション 2:バリデーション付きの文字列フィールドを使用する
// Instead of reference
{
type: 'string',
name: 'authorId',
label: 'Author ID',
ui: {
component: 'select',
options: ['author-1', 'author-2', 'author-3'] // Curated list
}
}
オプション 3:カスタムフィールドコンポーネント(上級者向け)
- カスタムコンポーネントでページネーションを実装します
- TinaCMS のドキュメントを参照してください:https://tina.io/docs/extending-tina/custom-field-components/
デプロイパターン
ニーズに合ったデプロイ方法を選択してください。
オプション 1:TinaCloud(マネージド)- 最も簡単 ⭐
おすすめの用途:すばやくセットアップしたい場合、無料枠を利用したい場合、インフラ管理を任せたい場合
手順:
- https://app.tina.io でアカウントを登録します
- プロジェクトを作成し、Client ID と Read Only Token を取得します
- 環境変数を設定します:
NEXT_PUBLIC_TINA_CLIENT_ID=your_client_id TINA_TOKEN=your_read_only_token - バックエンドを初期化します:
npx @tinacms/cli@latest init backend - ホスティングプロバイダー(Vercel、Netlify、Cloudflare Pages)にデプロイします
- Tina ダッシュボードでGitHub 連携を設定します
メリット:
- ✅ バックエンドの設定が不要です
- ✅ GraphQL API が自動で提供されます
- ✅ 認証機能が組み込まれています
- ✅ Git 連携が自動で処理されます
- ✅ 無料枠が充実しています(月間 10k リクエスト)
デメリット:
- ❌ 無料枠を超えると有料サービスになります
- ❌ ベンダーに依存します(ただし、コンテンツは引き続き Git に保存されます)
参考:references/deployment-guide.md#tinacloud を参照してください
オプション 2:Cloudflare Workers でセルフホスト 🔥
おすすめの用途:バックエンドを完全に制御したい場合、Cloudflare エコシステムを利用している場合、エッジにデプロイしたい場合
手順:
-
依存関係をインストールします:
npm install @tinacms/datalayer tinacms-authjs -
バックエンドを初期化します:
npx @tinacms/cli@latest init backend -
Workers エンドポイントを作成します:
// workers/src/index.ts import { TinaNodeBackend, LocalBackendAuthProvider } from '@tinacms/datalayer' import { AuthJsBackendAuthProvider, TinaAuthJSOptions } from 'tinacms-authjs' import databaseClient from '../../tina/__generated__/databaseClient' const isLocal = process.env.TINA_PUBLIC_IS_LOCAL === 'true' export default { async fetch(request: Request, env: Env) { const handler = TinaNodeBackend({ authProvider: isLocal ? LocalBackendAuthProvider() : AuthJsBackendAuthProvider({ authOptions: TinaAuthJSOptions({ databaseClient, secret: env.NEXTAUTH_SECRET, }), }), databaseClient, }) return handler(request) } } -
tina/config.tsを更新します:export default defineConfig({ contentApiUrlOverride: '/api/tina/gql', // Your Workers endpoint // ... rest of config }) -
wrangler.jsoncを設定します:{ "name": "tina-backend", "main": "workers/src/index.ts", "compatibility_date": "2025-10-24", "vars": { "TINA_PUBLIC_IS_LOCAL": "false" }, "env": { "production": { "vars": { "NEXTAUTH_SECRET": "your-secret-here" } } } } -
デプロイします:
npx wrangler deploy
メリット:
- ✅ バックエンドを完全に制御できます
- ✅ 無料枠が充実しています(1 日あたり 100k リクエスト)
- ✅ グローバルなエッジネットワークを利用できます(世界中で高速)
- ✅ ベンダーロックインがありません
デメリット:
- ❌ セットアップが複雑になります
- ❌ 認証設定が必要です
- ❌ Cloudflare Workers の知識が必要です
詳細ガイド:references/self-hosting-cloudflare.md を参照してください
テンプレート:templates/cloudflare-worker-backend/ を参照してください
オプション 3:Vercel Functions でセルフホスト
おすすめの用途:Next.js プロジェクト、Vercel エコシステム
手順:
-
依存関係をインストールします:
npm install @tinacms/datalayer tinacms-authjs -
API ルートを作成します:
// api/tina/backend.ts import { TinaNodeBackend, LocalBackendAuthProvider } from '@tinacms/datalayer' import { AuthJsBackendAuthProvider, TinaAuthJSOptions } from 'tinacms-authjs' import databaseClient from '../../../tina/__generated__/databaseClient' const isLocal = process.env.TINA_PUBLIC_IS_LOCAL === 'true' const handler = TinaNodeBackend({ authProvider: isLocal ? LocalBackendAuthProvider() : AuthJsBackendAuthProvider({ authOptions: TinaAuthJSOptions({ databaseClient, secret: process.env.NEXTAUTH_SECRET, }), }), databaseClient, }) export default handler -
vercel.jsonのリライトを作成します:{ "rewrites": [ { "source": "/api/tina/:path*", "destination": "/api/tina/backend" } ] } -
開発スクリプトを更新します:
{ "scripts": { "dev": "TINA_PUBLIC_IS_LOCAL=true tinacms dev -c \"next dev --port $PORT\"" } } -
Vercel ダッシュボードで環境変数を設定します:
NEXTAUTH_SECRET=your-secret TINA_PUBLIC_IS_LOCAL=false -
デプロイします:
vercel deploy
メリット:
- ✅ Next.js とネイティブに統合できます
- ✅ Vercel へのデプロイが簡単です
- ✅ サーバーレスです(自動的にスケールします)
デメリット:
- ❌ Vercel 専用です
- ❌ 関数に制限があります(タイムアウト 10 秒、サイズ 50MB)
参考:references/deployment-guide.md#vercel を参照してください
オプション 4:Netlify Functions でセルフホスト
手順:
-
依存関係をインストールします:
npm install express serverless-http @tinacms/datalayer tinacms-authjs -
関数を作成します:
// netlify/functions/tina.ts import express from 'express' import ServerlessHttp from 'serverless-http' import { TinaNodeBackend, LocalBackendAuthProvider } from '@tinacms/datalayer' import { AuthJsBackendAuthProvider, TinaAuthJSOptions } from 'tinacms-authjs' import databaseClient from '../../tina/__generated__/databaseClient' const app = express() app.use(express.json()) const tinaBackend = TinaNodeBackend({ authProvider: AuthJsBackendAuthProvider({ authOptions: TinaAuthJSOptions({ databaseClient, secret: process.env.NEXTAUTH_SECRET, }), }), databaseClient, }) app.post('/api/tina/*', tinaBackend) app.get('/api/tina/*', tinaBackend) export const handler = ServerlessHttp(app) -
netlify.tomlを作成します:[functions] node_bundler = "esbuild" [[redirects]] from = "/api/tina/*" to = "/.netlify/functions/tina" status = 200 force = true -
デプロイします:
netlify deploy --prod
参考:references/deployment-guide.md#netlify を参照してください
認証の設定
オプション 1:ローカル開発(デフォルト)
用途:ローカル開発、本番環境へのデプロイを行わない場合
// tina/__generated__/databaseClient or backend config
const isLocal = process.env.TINA_PUBLIC_IS_LOCAL === 'true'
authProvider: isLocal ? LocalBackendAuthProvider() : /* ... */
環境変数:
TINA_PUBLIC_IS_LOCAL=true
セキュリティ:認証はありません。ローカルでのみ使用してください!
オプション 2:Auth.js(セルフホストにおすすめ)
用途:OAuth プロバイダー(GitHub、Discord、Google など)を使ってセルフホストする場合
インストール:
npm install next-auth tinacms-authjs
設定:
import { AuthJsBackendAuthProvider, TinaAuthJSOptions } from 'tinacms-authjs'
import DiscordProvider from 'next-auth/providers/discord'
export const AuthOptions = TinaAuthJSOptions({
databaseClient,
secret: process.env.NEXTAUTH_SECRET,
providers: [
DiscordProvider({
clientId: process.env.DISCORD_CLIENT_ID,
clientSecret: process.env.DISCORD_CLIENT_SECRET,
}),
// Add GitHub, Google, etc.
],
})
const handler = TinaNodeBackend({
authProvider: AuthJsBackendAuthProvider({
authOptions: AuthOptions,
}),
databaseClient,
})
対応プロバイダー:GitHub、Discord、Google、Twitter、Facebook、Email など
参考:https://next-auth.js.org/providers/
オプション 3:TinaCloud Auth(マネージド)
用途:TinaCloud のホスティングサービスを利用する場合
import { TinaCloudBackendAuthProvider } from '@tinacms/auth'
authProvider: TinaCloudBackendAuthProvider()
設定:
- https://app.tina.io でアカウントを登録します
- プロジェクトを作成します
- ダッシュボードでユーザーを管理します
- 認証は自動的に処理されます
オプション 4:カスタム認証プロバイダー
用途:既存の認証システム、独自の要件がある場合
const CustomBackendAuth = () => {
return {
isAuthorized: async (req, res) => {
const token = req.headers.authorization
// Your validation logic
const user = await validateToken(token)
if (user && user.canEdit) {
return { isAuthorized: true }
}
return {
isAuthorized: false,
errorMessage: 'Unauthorized',
errorCode: 401
}
},
}
}
authProvider: CustomBackendAuth()
GraphQL API の使用
TinaCMS は、型安全な GraphQL クライアントを自動的に生成します。
データのクエリ
TinaCloud:
import client from '../tina/__generated__/client'
// Single document
const post = await client.queries.post({
relativePath: 'hello-world.md'
})
// Multiple documents
const posts = await client.queries.postConnection()
セルフホスト:
import client from '../tina/__generated__/databaseClient'
// Same API as TinaCloud client
const post = await client.queries.post({
relativePath: 'hello-world.md'
})
useTina Hook によるビジュアル編集
Next.js の例:
import { useTina } from 'tinacms/dist/react'
import { client } from '../../tina/__generated__/client'
export default function BlogPost(props) {
// Hydrate data for visual editing
const { data } = useTina({
query: props.query,
variables: props.variables,
data: props.data
})
return (
<article>
<h1>{data.post.title}</h1>
<p>{data.post.excerpt}</p>
<div dangerouslySetInnerHTML={{ __html: data.post.body }} />
</article>
)
}
export async function getStaticProps({ params }) {
const response = await client.queries.post({
relativePath: `${params.slug}.md`
})
return {
props: {
data: response.data,
query: response.query,
variables: response.variables
}
}
}
仕組み:
- 本番環境では、
useTinaは初期データを返します(オーバーヘッドはありません) - 編集モードでは、
useTinaは GraphQL に接続し、リアルタイムで更新します - 変更はプレビューにすぐに反映されます
その他のリソース
テンプレート
templates/nextjs/- Next.js App Router と Pages Router の設定templates/vite-react/- Vite + React のセットアップtemplates/astro/- Astro の統合templates/collections/- 事前構築済みのコレクションスキーマtemplates/cloudflare-worker-backend/- Cloudflare Workers でのセルフホスト
リファレンス
references/schema-patterns.md- 高度なスキーマモデリングのパターンreferences/field-types-reference.md- フィールド型の完全なドキュメントreferences/deployment-guide.md- すべてのプラットフォーム向けデプロイガイドreferences/self-hosting-cloudflare.md- Cloudflare Workers の完全ガイドreferences/common-errors.md- エラーの詳細なトラブルシューティングreferences/migration-guide.md- Forestry.io からの移行
スクリプト
scripts/init-nextjs.sh- Next.js の自動セットアップscripts/init-vite-react.sh- Vite + React の自動セットアップscripts/init-astro.sh- Astro の自動セットアップscripts/check-versions.sh- パッケージのバージョンを確認
公式ドキュメント
- ウェブサイト:https://tina.io
- ドキュメント:https://tina.io/docs
- GitHub:https://github.com/tinacms/tinacms
- Discord:https://discord.gg/zumN63Ybpf
トークン効率
推定削減率:65~70%(10,900 トークン削減)
スキルなし(約16,000トークン):
- 初期調査と探索:3,000トークン
- フレームワークのセットアップにおける試行錯誤:2,500トークン
- スキーマモデリングの試行:2,000トークン
- エラーのトラブルシューティング:4,000トークン
- デプロイ設定:2,500トークン
- 認証のセットアップ:2,000トークン
スキルあり(約5,100トークン):
- スキルの発見:100トークン
- スキルの読み込み(SKILL.md):3,000トークン
- テンプレートの選択:500トークン
- プロジェクト固有の軽微な調整:1,500トークン
防止できるエラー
このスキルにより、9つのよくあるエラーを防止できます(防止率100%)。
- ✅ ESbuild のコンパイルエラー(インポートの問題)
- ✅ モジュール解決の問題
- ✅ フィールド名の制約違反
- ✅ Docker のバインドの問題
- ✅
_templateキーの欠落エラー - ✅ パスの不一致の問題
- ✅ ビルドスクリプトの実行順序に関する失敗
- ✅ 本番環境でのアセット読み込みエラー
- ✅ Reference フィールドの 503 タイムアウト
クイックスタートの例
例1:Next.js + TinaCloud を使ったブログ
# 1. Create Next.js app
npx create-next-app@latest my-blog --typescript --app
# 2. Initialize TinaCMS
cd my-blog
npx @tinacms/cli@latest init
# 3. Set environment variables
echo "NEXT_PUBLIC_TINA_CLIENT_ID=your_client_id" >> .env.local
echo "TINA_TOKEN=your_token" >> .env.local
# 4. Start dev server
npm run dev
# 5. Access admin
open http://localhost:3000/admin/index.html
例2:Astro を使ったドキュメントサイト
# 1. Use official starter
npx create-tina-app@latest my-docs --template tina-astro-starter
# 2. Install dependencies
cd my-docs
npm install
# 3. Start dev server
npm run dev
# 4. Access admin
open http://localhost:4321/admin/index.html
例3:Cloudflare Workers でのセルフホスト
# 1. Initialize project
npm create cloudflare@latest my-app
# 2. Add TinaCMS
npx @tinacms/cli@latest init
npx @tinacms/cli@latest init backend
# 3. Install dependencies
npm install @tinacms/datalayer tinacms-authjs
# 4. Copy Cloudflare Workers backend template
cp -r [path-to-skill]/templates/cloudflare-worker-backend/* workers/
# 5. Configure and deploy
npx wrangler deploy
本番環境での使用例
- TinaCMS のウェブサイト:https://tina.io(ドッグフーディング)
- Astro Starter:https://github.com/tinacms/tina-astro-starter
- Next.js Starter:https://github.com/tinacms/tina-starter-alpaca
サポート
問題がありますか? まず references/common-errors.md を確認してください
まだ解決しませんか?
- Discord:https://discord.gg/zumN63Ybpf
- GitHub Issues:https://github.com/tinacms/tinacms/issues
- 公式ドキュメント:https://tina.io/docs
最終更新日:2025-10-24 スキルのバージョン:1.0.0 TinaCMS のバージョン:2.9.0 CLI のバージョン:1.11.0