tinacms by jezweb/claude-skills
npx skills add https://github.com/jezweb/claude-skills --skill tinacms基于 Git 的无头内容管理系统,为内容密集型网站提供可视化编辑功能。
最后更新:2026-01-21 版本:tinacms@3.3.1, @tinacms/cli@2.1.1
包管理器推荐:
推荐:pnpm (TinaCMS >2.7.3 必需)
备选:npm 或 yarn (新版本中可能存在模块解析问题)
npm install -g pnpm
npx @tinacms/cli@latest init
pnpm install
{ "dev": "tinacms dev -c "next dev"", "build": "tinacms build && next build" }
NEXT_PUBLIC_TINA_CLIENT_ID=your_client_id TINA_TOKEN=your_read_only_token
pnpm run dev
版本锁定 (推荐):
锁定确切版本以防止自动 CLI/UI 更新导致的破坏性变更:
{
"dependencies": {
"tinacms": "3.3.1", // 不是 "^3.3.1"
"@tinacms/cli": "2.1.1"
}
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
原因:TinaCMS UI 资源从 CDN 提供,可能在您的本地 CLI 之前更新,导致不兼容。
useTina Hook (启用可视化编辑):
import { useTina } from 'tinacms/dist/react'
import { client } from '../../tina/__generated__/client'
export default function BlogPost(props) {
const { data } = useTina({
query: props.query,
variables: props.variables,
data: props.data
})
return <article><h1>{data.post.title}</h1></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
}
}
}
App Router:管理路由在 app/admin/[[...index]]/page.tsx Pages Router:管理路由在 pages/admin/[[...index]].tsx
tina/config.ts 结构:
import { defineConfig } from 'tinacms'
export default defineConfig({
branch: process.env.GITHUB_BRANCH || 'main',
clientId: process.env.NEXT_PUBLIC_TINA_CLIENT_ID,
token: process.env.TINA_TOKEN,
build: {
outputFolder: 'admin',
publicFolder: 'public',
},
schema: {
collections: [/* ... */],
},
})
集合示例 (博客文章):
{
name: 'post', // 仅限字母数字和下划线
label: '博客文章',
path: 'content/posts', // 无尾部斜杠
format: 'mdx',
fields: [
{
type: 'string',
name: 'title',
label: '标题',
isTitle: true,
required: true
},
{
type: 'rich-text',
name: 'body',
label: '正文',
isBody: true
}
]
}
字段类型:string、rich-text、number、datetime、boolean、image、reference、object
引用字段注意事项:当引用字段引用具有共享字段名的多个集合类型时,请确保字段类型匹配。冲突的类型(例如 bio: string 与 bio: rich-text)会导致 GraphQL 模式错误。
// 示例:引用多个集合的引用字段
{
type: 'reference',
name: 'contributor',
collections: ['author', 'editor'] // 确保共享字段具有相同类型
}
来源:社区收集
错误信息:
ERROR: Schema Not Successfully Built
ERROR: Config Not Successfully Executed
原因:
window、DOM API、React hooks)解决方案:
仅导入所需内容:
// ❌ 错误 - 导入整个组件目录
import { HeroComponent } from '../components/'
// ✅ 正确 - 导入特定文件
import { HeroComponent } from '../components/blocks/hero'
预防提示:
tina/config.ts 导入最小化.schema.ts 文件参考:参见 references/common-errors.md#esbuild
错误信息:
Error: Could not resolve "tinacms"
原因:
解决方案:
# 清除缓存并重新安装
rm -rf node_modules package-lock.json
npm install
# 或使用 pnpm
rm -rf node_modules pnpm-lock.yaml
pnpm install
# 或使用 yarn
rm -rf node_modules yarn.lock
yarn install
预防措施:
package-lock.json、pnpm-lock.yaml、yarn.lock)--no-optional 或 --omit=optional 标志react 和 react-dom(即使对于非 React 框架)错误信息:
Field name contains invalid characters
原因:
解决方案:
// ❌ 错误 - 使用连字符
{
name: 'hero-image',
label: 'Hero Image',
type: 'image'
}
// ❌ 错误 - 使用空格
{
name: 'hero image',
label: 'Hero Image',
type: 'image'
}
// ✅ 正确 - 使用下划线
{
name: 'hero_image',
label: 'Hero Image',
type: 'image'
}
// ✅ 正确 - CamelCase 也有效
{
name: 'heroImage',
label: 'Hero Image',
type: 'image'
}
注意:这是从 Forestry.io 迁移的破坏性变更
错误:
原因:
127.0.0.1(仅限本地主机)0.0.0.0 以接受外部连接解决方案:
# 确保框架开发服务器监听所有接口
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 # 运行:tinacms dev -c "next dev --hostname 0.0.0.0"
_template 键错误错误信息:
GetCollection failed: Unable to fetch
template name was not provided
原因:
templates 数组(多个模式)_template 字段templates 迁移到 fields 但文档未更新解决方案:
选项 1:使用fields 代替(推荐用于单一模板)
{
name: 'post',
path: 'content/posts',
fields: [/* ... */] // 不需要 _template
}
选项 2:确保 frontmatter 中存在_template
---
_template: article # ← 使用 templates 数组时必需
title: 我的文章
---
迁移脚本(如果从 templates 转换为 fields):
# 从 content/posts/ 中的所有文件中移除 _template
find content/posts -name "*.md" -exec sed -i '/_template:/d' {} +
错误:
原因:
path 与实际文件目录不匹配解决方案:
// 文件位于:content/posts/hello.md
// ✅ 正确
{
name: 'post',
path: 'content/posts', // 匹配文件位置
fields: [/* ... */]
}
// ❌ 错误 - 缺少 'content/'
{
name: 'post',
path: 'posts', // 找不到文件
fields: [/* ... */]
}
// ❌ 错误 - 尾部斜杠
{
name: 'post',
path: 'content/posts/', // 可能导致问题
fields: [/* ... */]
}
调试:
npx @tinacms/cli@latest audit 检查路径format 字段匹配错误信息:
ERROR: Cannot find module '../tina/__generated__/client'
ERROR: Property 'queries' does not exist on type '{}'
原因:
tinacms build 之前运行解决方案:
{
"scripts": {
"build": "tinacms build && next build" // ✅ Tina 优先
// 不是:"build": "next build && tinacms build" // ❌ 错误顺序
}
}
CI/CD 示例 (GitHub Actions):
- name: 构建
run: |
npx @tinacms/cli@latest build # 首先生成类型
npm run build # 然后构建框架
为何重要:
tinacms build 在 tina/__generated__/ 中生成 TypeScript 类型错误信息:
Failed to load resource: net::ERR_CONNECTION_REFUSED
http://localhost:4001/...
原因:
admin/index.html 推送到了生产环境(从 localhost 加载资源)basePath解决方案:
对于生产部署:
{
"scripts": {
"build": "tinacms build && next build" // ✅ 始终构建
// 不是:"build": "tinacms dev" // ❌ 生产环境切勿使用 dev
}
}
对于子目录部署:
⚠️ 子路径部署限制:当部署到子路径时(例如
example.com/cms/admin而不是example.com/admin),TinaCMS 存在正确加载资源的已知问题。即使配置了basePath,这也是一个限制。变通方案:将 TinaCMS 管理界面部署在根路径 (
/admin) 或使用反向代理重写规则。来源:社区收集
// tina/config.ts
export default defineConfig({
build: {
outputFolder: 'admin',
publicFolder: 'public',
basePath: 'your-subdirectory' // ← 在子路径上可能存在资源加载问题
}
})
CI/CD 修复:
# GitHub Actions / Vercel / Netlify
- run: npx @tinacms/cli@latest build # 始终使用 build,而不是 dev
错误:
原因:
解决方案:
选项 1:拆分集合
// 不要使用一个庞大的 "authors" 集合
// 按活动状态或字母顺序拆分
{
name: 'active_author',
label: '活跃作者',
path: 'content/authors/active',
fields: [/* ... */]
}
{
name: 'archived_author',
label: '已归档作者',
path: 'content/authors/archived',
fields: [/* ... */]
}
选项 2:使用带验证的字符串字段
// 代替引用
{
type: 'string',
name: 'authorId',
label: '作者 ID',
ui: {
component: 'select',
options: ['author-1', 'author-2', 'author-3'] // 精选列表
}
}
选项 3:自定义字段组件 (高级)
错误信息:
Upload failed
Error uploading image
原因:
解决方案:
如果上传显示错误:
状态:已知问题(高优先级) 来源:GitHub Issue #6325
设置:
NEXT_PUBLIC_TINA_CLIENT_ID、TINA_TOKEN优点:零配置,免费套餐(每月 10k 请求)
⚠️ Edge Runtime 限制:自托管的 TinaCMS 在 Edge Runtime 环境(Cloudflare Workers、Vercel Edge Functions)中无法工作,因为
@tinacms/datalayer和@tinacms/graphql依赖 Node.js。对于边缘部署,请使用 TinaCloud(托管服务)。来源:GitHub Issue #4363 (标记为 "wontfix")
⚠️ 自托管示例可能已过时:TinaCMS 团队承认官方仓库中的自托管示例"相当过时"。请始终与最新文档交叉参考,而不是仅仅依赖示例仓库。
仅适用于 Node.js 环境(非 edge runtime):
pnpm install @tinacms/datalayer tinacms-authjs
npx @tinacms/cli@latest init backend
示例 (Node.js 服务器,非 Workers):
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'
// 这仅适用于 Node.js runtime,不适用于 edge runtime
const handler = TinaNodeBackend({
authProvider: isLocal
? LocalBackendAuthProvider()
: AuthJsBackendAuthProvider({
authOptions: TinaAuthJSOptions({
databaseClient,
secret: process.env.NEXTAUTH_SECRET,
}),
}),
databaseClient,
})
优点:完全控制,自托管 缺点:需要 Node.js runtime(无法使用边缘计算)
每周安装次数
304
仓库
GitHub 星标
650
首次出现
2026年1月20日
安全审计
已安装于
claude-code257
gemini-cli204
opencode200
cursor194
antigravity187
codex175
Git-backed headless CMS with visual editing for content-heavy sites.
Last Updated : 2026-01-21 Versions : tinacms@3.3.1, @tinacms/cli@2.1.1
Package Manager Recommendation:
Recommended : pnpm (required for TinaCMS >2.7.3)
Alternative : npm or yarn (may have module resolution issues in newer versions)
npm install -g pnpm
npx @tinacms/cli@latest init
pnpm install
{ "dev": "tinacms dev -c "next dev"", "build": "tinacms build && next build" }
NEXT_PUBLIC_TINA_CLIENT_ID=your_client_id TINA_TOKEN=your_read_only_token
pnpm run dev
Version Locking (Recommended):
Pin exact versions to prevent breaking changes from automatic CLI/UI updates:
{
"dependencies": {
"tinacms": "3.3.1", // NOT "^3.3.1"
"@tinacms/cli": "2.1.1"
}
}
Why : TinaCMS UI assets are served from CDN and may update before your local CLI, causing incompatibilities.
Source : GitHub Issue #5838
useTina Hook (enables visual editing):
import { useTina } from 'tinacms/dist/react'
import { client } from '../../tina/__generated__/client'
export default function BlogPost(props) {
const { data } = useTina({
query: props.query,
variables: props.variables,
data: props.data
})
return <article><h1>{data.post.title}</h1></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
}
}
}
App Router : Admin route at app/admin/[[...index]]/page.tsx Pages Router : Admin route at pages/admin/[[...index]].tsx
tina/config.ts structure:
import { defineConfig } from 'tinacms'
export default defineConfig({
branch: process.env.GITHUB_BRANCH || 'main',
clientId: process.env.NEXT_PUBLIC_TINA_CLIENT_ID,
token: process.env.TINA_TOKEN,
build: {
outputFolder: 'admin',
publicFolder: 'public',
},
schema: {
collections: [/* ... */],
},
})
Collection Example (Blog Post):
{
name: 'post', // Alphanumeric + underscores only
label: 'Blog Posts',
path: 'content/posts', // No trailing slash
format: 'mdx',
fields: [
{
type: 'string',
name: 'title',
label: 'Title',
isTitle: true,
required: true
},
{
type: 'rich-text',
name: 'body',
label: 'Body',
isBody: true
}
]
}
Field Types : string, rich-text, number, datetime, boolean, image, reference, object
Reference Field Note : When a reference field references multiple collection types with shared field names, ensure the field types match. Conflicting types (e.g., bio: string vs bio: rich-text) cause GraphQL schema errors.
// Example: Reference field referencing multiple collections
{
type: 'reference',
name: 'contributor',
collections: ['author', 'editor'] // Ensure shared fields have same type
}
Source : Community-sourced
Error Message:
ERROR: Schema Not Successfully Built
ERROR: Config Not Successfully Executed
Causes:
window, DOM APIs, React hooks)Solution:
Import only what you need:
// ❌ Bad - Imports entire component directory
import { HeroComponent } from '../components/'
// ✅ Good - Import specific file
import { HeroComponent } from '../components/blocks/hero'
Prevention Tips:
tina/config.ts imports minimal.schema.ts files if neededReference : See references/common-errors.md#esbuild
Error Message:
Error: Could not resolve "tinacms"
Causes:
Solution:
# 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
Prevention:
package-lock.json, pnpm-lock.yaml, yarn.lock)--no-optional or --omit=optional flagsreact and react-dom are installed (even for non-React frameworks)Error Message:
Field name contains invalid characters
Cause:
Solution:
// ❌ 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'
}
Note : This is a breaking change from Forestry.io migration
Error:
Cause:
127.0.0.1 (localhost only) by default0.0.0.0 binding to accept external connectionsSolution:
# 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 Example:
services:
app:
build: .
ports:
- "3000:3000"
command: npm run dev # Which runs: tinacms dev -c "next dev --hostname 0.0.0.0"
_template Key ErrorError Message:
GetCollection failed: Unable to fetch
template name was not provided
Cause:
templates array (multiple schemas)_template field in frontmattertemplates to fields and documents not updatedSolution:
Option 1: Usefields instead (recommended for single template)
{
name: 'post',
path: 'content/posts',
fields: [/* ... */] // No _template needed
}
Option 2: Ensure_template exists in frontmatter
---
_template: article # ← Required when using templates array
title: My Post
---
Migration Script (if converting from templates to fields):
# Remove _template from all files in content/posts/
find content/posts -name "*.md" -exec sed -i '/_template:/d' {} +
Error:
Cause:
path in collection config doesn't match actual file directorySolution:
// 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: [/* ... */]
}
Debugging:
npx @tinacms/cli@latest audit to check pathsformat fieldError Message:
ERROR: Cannot find module '../tina/__generated__/client'
ERROR: Property 'queries' does not exist on type '{}'
Cause:
tinacms buildSolution:
{
"scripts": {
"build": "tinacms build && next build" // ✅ Tina FIRST
// NOT: "build": "next build && tinacms build" // ❌ Wrong order
}
}
CI/CD Example (GitHub Actions):
- name: Build
run: |
npx @tinacms/cli@latest build # Generate types first
npm run build # Then build framework
Why This Matters:
tinacms build generates TypeScript types in tina/__generated__/Error Message:
Failed to load resource: net::ERR_CONNECTION_REFUSED
http://localhost:4001/...
Causes:
admin/index.html to production (loads assets from localhost)basePath not configuredSolution:
For Production Deploys:
{
"scripts": {
"build": "tinacms build && next build" // ✅ Always build
// NOT: "build": "tinacms dev" // ❌ Never dev in production
}
}
For Subdirectory Deployments:
⚠️ Sub-path Deployment Limitation : TinaCMS has known issues loading assets correctly when deployed to a sub-path (e.g.,
example.com/cms/admininstead ofexample.com/admin). This is a limitation even withbasePathconfiguration.Workaround : Deploy TinaCMS admin at root path (
/admin) or use reverse proxy rewrite rules.Source : Community-sourced
// tina/config.ts
export default defineConfig({
build: {
outputFolder: 'admin',
publicFolder: 'public',
basePath: 'your-subdirectory' // ← May have asset loading issues on sub-paths
}
})
CI/CD Fix:
# GitHub Actions / Vercel / Netlify
- run: npx @tinacms/cli@latest build # Always use build, not dev
Error:
Cause:
Solutions:
Option 1: Split collections
// 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: [/* ... */]
}
Option 2: Use string field with validation
// Instead of reference
{
type: 'string',
name: 'authorId',
label: 'Author ID',
ui: {
component: 'select',
options: ['author-1', 'author-2', 'author-3'] // Curated list
}
}
Option 3: Custom field component (advanced)
Error Message:
Upload failed
Error uploading image
Cause:
Solution:
If upload shows error:
Status : Known issue (high priority) Source : GitHub Issue #6325
Setup:
NEXT_PUBLIC_TINA_CLIENT_ID, TINA_TOKENPros : Zero config, free tier (10k requests/month)
⚠️ Edge Runtime Limitation : Self-hosted TinaCMS does NOT work in Edge Runtime environments (Cloudflare Workers, Vercel Edge Functions) due to Node.js dependencies in
@tinacms/datalayerand@tinacms/graphql. Use TinaCloud (managed service) for edge deployments.Source : GitHub Issue #4363 (labeled "wontfix")
⚠️ Self-Hosted Examples May Be Outdated : Official self-hosted examples in the TinaCMS repository are acknowledged by the team as "quite out of date". Always cross-reference with latest documentation instead of relying solely on example repos.
Source : GitHub Issue #6365
For Node.js environments only (not edge runtime):
pnpm install @tinacms/datalayer tinacms-authjs
npx @tinacms/cli@latest init backend
Example (Node.js server, not Workers) :
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'
// This ONLY works in Node.js runtime, NOT edge runtime
const handler = TinaNodeBackend({
authProvider: isLocal
? LocalBackendAuthProvider()
: AuthJsBackendAuthProvider({
authOptions: TinaAuthJSOptions({
databaseClient,
secret: process.env.NEXTAUTH_SECRET,
}),
}),
databaseClient,
})
Pros : Full control, self-hosted Cons : Requires Node.js runtime (cannot use edge computing)
Weekly Installs
304
Repository
GitHub Stars
650
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
claude-code257
gemini-cli204
opencode200
cursor194
antigravity187
codex175
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
105,000 周安装