tinacms

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

TinaCMS

TinaCMS

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

基于Git的无头CMS,为内容密集型网站提供可视化编辑功能。
最后更新时间:2026-01-21 版本:tinacms@3.3.1, @tinacms/cli@2.1.1

Quick Start

快速开始

Package Manager Recommendation:
  • Recommended: pnpm (required for TinaCMS >2.7.3)
  • Alternative: npm or yarn (may have module resolution issues in newer versions)
bash
undefined
包管理器推荐:
  • 推荐:pnpm(TinaCMS >2.7.3版本要求使用)
  • 替代方案:npm或yarn(新版本中可能存在模块解析问题)
bash
undefined

Install pnpm (if needed)

安装pnpm(如有需要)

npm install -g pnpm
npm install -g pnpm

Initialize TinaCMS

初始化TinaCMS

npx @tinacms/cli@latest init
npx @tinacms/cli@latest init

Install dependencies with pnpm

使用pnpm安装依赖

pnpm install
pnpm install

Update package.json scripts

更新package.json中的脚本

{ "dev": "tinacms dev -c "next dev"", "build": "tinacms build && next build" }
{ "dev": "tinacms dev -c "next dev"", "build": "tinacms build && next build" }

Set environment variables

设置环境变量

NEXT_PUBLIC_TINA_CLIENT_ID=your_client_id TINA_TOKEN=your_read_only_token
NEXT_PUBLIC_TINA_CLIENT_ID=your_client_id TINA_TOKEN=your_read_only_token

Start dev server

启动开发服务器

pnpm run dev
pnpm run dev

Access admin interface

访问管理界面


**Version Locking (Recommended):**

Pin exact versions to prevent breaking changes from automatic CLI/UI updates:

```json
{
  "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.


**版本锁定(推荐):**

固定精确版本,防止CLI/UI自动更新导致的破坏性变更:

```json
{
  "dependencies": {
    "tinacms": "3.3.1",  // 不要使用"^3.3.1"
    "@tinacms/cli": "2.1.1"
  }
}
原因:TinaCMS UI资源从CDN加载,可能会先于本地CLI更新,导致兼容性问题。

Next.js Integration

Next.js集成

useTina Hook (enables visual editing):
tsx
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

useTina Hook(启用可视化编辑):
tsx
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

Schema Configuration

Schema配置

tina/config.ts structure:
typescript
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):
typescript
{
  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.
typescript
// Example: Reference field referencing multiple collections
{
  type: 'reference',
  name: 'contributor',
  collections: ['author', 'editor']  // Ensure shared fields have same type
}

tina/config.ts结构:
typescript
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: [/* ... */],
  },
})
集合示例(博客文章):
typescript
{
  name: 'post',           // 仅允许字母、数字和下划线
  label: 'Blog Posts',
  path: 'content/posts',  // 不要加末尾斜杠
  format: 'mdx',
  fields: [
    {
      type: 'string',
      name: 'title',
      label: 'Title',
      isTitle: true,
      required: true
    },
    {
      type: 'rich-text',
      name: 'body',
      label: 'Body',
      isBody: true
    }
  ]
}
字段类型
string
,
rich-text
,
number
,
datetime
,
boolean
,
image
,
reference
,
object
引用字段注意事项:当引用字段引用多个具有共享字段名的集合类型时,确保字段类型一致。类型冲突(如
bio: string
vs
bio: rich-text
)会导致GraphQL schema错误。
typescript
// 示例:引用多个集合的引用字段
{
  type: 'reference',
  name: 'contributor',
  collections: ['author', 'editor']  // 确保共享字段类型一致
}
来源社区整理

Common Errors & Solutions

常见错误与解决方案

1. ❌ ESbuild Compilation Errors

1. ❌ ESbuild编译错误

Error Message:
ERROR: Schema Not Successfully Built
ERROR: Config Not Successfully Executed
Causes:
  • Importing code with custom loaders (webpack, babel plugins, esbuild loaders)
  • Importing frontend-only code (uses
    window
    , DOM APIs, React hooks)
  • Importing entire component libraries instead of specific modules
Solution:
Import only what you need:
typescript
// ❌ Bad - Imports entire component directory
import { HeroComponent } from '../components/'

// ✅ Good - Import specific file
import { HeroComponent } from '../components/blocks/hero'
Prevention Tips:
  • Keep
    tina/config.ts
    imports minimal
  • Only import type definitions and simple utilities
  • Avoid importing UI components directly
  • Create separate
    .schema.ts
    files if needed
Reference: See
references/common-errors.md#esbuild

错误信息:
ERROR: Schema Not Successfully Built
ERROR: Config Not Successfully Executed
原因:
  • 导入了使用自定义加载器的代码(webpack、babel插件、esbuild加载器)
  • 导入了仅前端可用的代码(使用
    window
    、DOM API、React钩子)
  • 导入了整个组件库而非特定模块
解决方案:
仅导入所需内容:
typescript
// ❌ 错误示例 - 导入整个组件目录
import { HeroComponent } from '../components/'

// ✅ 正确示例 - 导入特定文件
import { HeroComponent } from '../components/blocks/hero'
预防技巧:
  • 尽量减少
    tina/config.ts
    中的导入
  • 仅导入类型定义和简单工具类
  • 避免直接导入UI组件
  • 如有需要,创建单独的
    .schema.ts
    文件
参考:查看
references/common-errors.md#esbuild

2. ❌ Module Resolution: "Could not resolve 'tinacms'"

2. ❌ 模块解析错误:"Could not resolve 'tinacms'"

Error Message:
Error: Could not resolve "tinacms"
Causes:
  • Corrupted or incomplete installation
  • Version mismatch between dependencies
  • Missing peer dependencies
Solution:
bash
undefined
错误信息:
Error: Could not resolve "tinacms"
原因:
  • 安装文件损坏或不完整
  • 依赖版本不匹配
  • 缺少对等依赖
解决方案:
bash
undefined

Clear cache and reinstall

清除缓存并重新安装

rm -rf node_modules package-lock.json npm install
rm -rf node_modules package-lock.json npm install

Or with pnpm

或使用pnpm

rm -rf node_modules pnpm-lock.yaml pnpm install
rm -rf node_modules pnpm-lock.yaml pnpm install

Or with yarn

或使用yarn

rm -rf node_modules yarn.lock yarn install

**Prevention:**
- Use lockfiles (`package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`)
- Don't use `--no-optional` or `--omit=optional` flags
- Ensure `react` and `react-dom` are installed (even for non-React frameworks)

---
rm -rf node_modules yarn.lock yarn install

**预防措施:**
- 使用锁文件(`package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`)
- 不要使用`--no-optional`或`--omit=optional`参数
- 确保已安装`react`和`react-dom`(即使是非React框架)

---

3. ❌ Field Naming Constraints

3. ❌ 字段命名限制

Error Message:
Field name contains invalid characters
Cause:
  • TinaCMS field names can only contain: letters, numbers, underscores
  • Hyphens, spaces, special characters are NOT allowed
Solution:
typescript
// ❌ 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

错误信息:
Field name contains invalid characters
原因:
  • TinaCMS字段名称仅允许包含:字母、数字、下划线
  • 不允许使用连字符、空格、特殊字符
解决方案:
typescript
// ❌ 错误示例 - 使用连字符
{
  name: 'hero-image',
  label: 'Hero Image',
  type: 'image'
}

// ❌ 错误示例 - 使用空格
{
  name: 'hero image',
  label: 'Hero Image',
  type: 'image'
}

// ✅ 正确示例 - 使用下划线
{
  name: 'hero_image',
  label: 'Hero Image',
  type: 'image'
}

// ✅ 正确示例 - 使用驼峰命名
{
  name: 'heroImage',
  label: 'Hero Image',
  type: 'image'
}
注意:这是从Forestry.io迁移时的一个破坏性变更

4. ❌ Docker Binding Issues

4. ❌ Docker绑定问题

Error:
  • TinaCMS admin not accessible from outside Docker container
Cause:
  • TinaCMS binds to
    127.0.0.1
    (localhost only) by default
  • Docker containers need
    0.0.0.0
    binding to accept external connections
Solution:
bash
undefined
错误:
  • TinaCMS管理界面无法从Docker容器外部访问
原因:
  • TinaCMS默认绑定到
    127.0.0.1
    (仅本地访问)
  • Docker容器需要绑定到
    0.0.0.0
    以接受外部连接
解决方案:
bash
// 确保框架开发服务器监听所有接口
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示例:
yaml
services:
  app:
    build: .
    ports:
      - "3000:3000"
    command: npm run dev  // 对应执行:tinacms dev -c "next dev --hostname 0.0.0.0"

Ensure framework dev server listens on all interfaces

5. ❌ 缺少
_template
键错误

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:**
```yaml
services:
  app:
    build: .
    ports:
      - "3000:3000"
    command: npm run dev  # Which runs: tinacms dev -c "next dev --hostname 0.0.0.0"

错误信息:
GetCollection failed: Unable to fetch
template name was not provided
原因:
  • 集合使用了
    templates
    数组(多schema)
  • 文档的frontmatter中缺少
    _template
    字段
  • templates
    迁移到
    fields
    但未更新文档
解决方案:
选项1:使用
fields
替代(单模板推荐)
typescript
{
  name: 'post',
  path: 'content/posts',
  fields: [/* ... */]  // 不需要_template
}
选项2:确保frontmatter中存在
_template
yaml
---
_template: article  // ← 使用templates数组时必填
title: My Post
---
迁移脚本(从templates转换为fields时使用):
bash
undefined

5. ❌ Missing
_template
Key Error

移除content/posts/所有文件中的_template字段

Error Message:
GetCollection failed: Unable to fetch
template name was not provided
Cause:
  • Collection uses
    templates
    array (multiple schemas)
  • Document missing
    _template
    field in frontmatter
  • Migrating from
    templates
    to
    fields
    and documents not updated
Solution:
Option 1: Use
fields
instead (recommended for single template)
typescript
{
  name: 'post',
  path: 'content/posts',
  fields: [/* ... */]  // No _template needed
}
Option 2: Ensure
_template
exists in frontmatter
yaml
---
_template: article  # ← Required when using templates array
title: My Post
---
Migration Script (if converting from templates to fields):
bash
undefined
find content/posts -name "*.md" -exec sed -i '/_template:/d' {} +

---

Remove _template from all files in content/posts/

6. ❌ 路径不匹配问题

find content/posts -name "*.md" -exec sed -i '/_template:/d' {} +

---
错误:
  • 文件未显示在Tina管理界面中
  • 保存时出现“文件未找到”错误
  • GraphQL查询返回空结果
原因:
  • 集合配置中的
    path
    与实际文件目录不匹配
  • 相对路径与绝对路径混淆
  • 末尾斜杠问题
解决方案:
typescript
// 文件实际位置:content/posts/hello.md

// ✅ 正确配置
{
  name: 'post',
  path: 'content/posts',  // 与文件位置匹配
  fields: [/* ... */]
}

// ❌ 错误配置 - 缺少'content/'
{
  name: 'post',
  path: 'posts',  // 无法找到文件
  fields: [/* ... */]
}

// ❌ 错误配置 - 末尾有斜杠
{
  name: 'post',
  path: 'content/posts/',  // 可能导致问题
  fields: [/* ... */]
}
调试方法:
  1. 运行
    npx @tinacms/cli@latest audit
    检查路径
  2. 验证文件是否存在于指定目录
  3. 检查文件扩展名是否与
    format
    字段匹配

6. ❌ Path Mismatch Issues

7. ❌ 构建脚本顺序问题

Error:
  • Files not appearing in Tina admin
  • "File not found" errors when saving
  • GraphQL queries return empty results
Cause:
  • path
    in collection config doesn't match actual file directory
  • Relative vs absolute path confusion
  • Trailing slash issues
Solution:
typescript
// 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:
  1. Run
    npx @tinacms/cli@latest audit
    to check paths
  2. Verify files exist in specified directory
  3. Check file extensions match
    format
    field

错误信息:
ERROR: Cannot find module '../tina/__generated__/client'
ERROR: Property 'queries' does not exist on type '{}'
原因:
  • 框架构建在
    tinacms build
    之前执行
  • Tina类型在TypeScript编译前未生成
  • CI/CD流水线顺序错误
解决方案:
json
{
  "scripts": {
    "build": "tinacms build && next build"  // ✅ 先执行Tina构建
    // 错误示例:"build": "next build && tinacms build"  // ❌ 顺序错误
  }
}
CI/CD示例(GitHub Actions):
yaml
- name: Build
  run: |
    npx @tinacms/cli@latest build  // 先生成类型
    npm run build                   // 再构建框架
重要性:
  • tinacms build
    会在
    tina/__generated__/
    目录生成TypeScript类型
  • 框架构建需要这些类型才能成功编译
  • 顺序错误会导致类型错误

7. ❌ Build Script Ordering Problems

8. ❌ TinaCMS资源加载失败

Error Message:
ERROR: Cannot find module '../tina/__generated__/client'
ERROR: Property 'queries' does not exist on type '{}'
Cause:
  • Framework build running before
    tinacms build
  • Tina types not generated before TypeScript compilation
  • CI/CD pipeline incorrect order
Solution:
json
{
  "scripts": {
    "build": "tinacms build && next build"  // ✅ Tina FIRST
    // NOT: "build": "next build && tinacms build"  // ❌ Wrong order
  }
}
CI/CD Example (GitHub Actions):
yaml
- 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__/
  • Framework build needs these types to compile successfully
  • Running in wrong order causes type errors

错误信息:
Failed to load resource: net::ERR_CONNECTION_REFUSED
http://localhost:4001/...
原因:
  • 将开发环境的
    admin/index.html
    推送到生产环境(从localhost加载资源)
  • 网站部署在子目录但未配置
    basePath
解决方案:
生产部署注意:
json
{
  "scripts": {
    "build": "tinacms build && next build"  // ✅ 始终使用build命令
    // 错误示例:"build": "tinacms dev"          // ❌ 生产环境绝不能用dev
  }
}
子目录部署注意:
⚠️ 子路径部署限制:TinaCMS部署到子路径时(如
example.com/cms/admin
而非
example.com/admin
),资源加载存在已知问题。即使配置了
basePath
也可能出现问题。
解决方法:将TinaCMS管理界面部署在根路径(
/admin
),或使用反向代理重写规则。
来源社区整理
typescript
// tina/config.ts
export default defineConfig({
  build: {
    outputFolder: 'admin',
    publicFolder: 'public',
    basePath: 'your-subdirectory'  // ← 子路径下可能存在资源加载问题
  }
})
CI/CD修复:
yaml
undefined

8. ❌ Failed Loading TinaCMS Assets

GitHub Actions / Vercel / Netlify

Error Message:
Failed to load resource: net::ERR_CONNECTION_REFUSED
http://localhost:4001/...
Causes:
  • Pushed development
    admin/index.html
    to production (loads assets from localhost)
  • Site served on subdirectory but
    basePath
    not configured
Solution:
For Production Deploys:
json
{
  "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/admin
instead of
example.com/admin
). This is a limitation even with
basePath
configuration.
Workaround: Deploy TinaCMS admin at root path (
/admin
) or use reverse proxy rewrite rules.
typescript
// 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:
yaml
undefined
  • run: npx @tinacms/cli@latest build // 始终使用build,不要用dev

---

GitHub Actions / Vercel / Netlify

9. ❌ 引用字段503服务不可用

  • run: npx @tinacms/cli@latest build # Always use build, not dev

---
错误:
  • 引用字段下拉框超时并显示503错误
  • 加载引用字段时管理界面无响应
原因:
  • 被引用的集合中条目过多(数百或数千条)
  • 引用字段目前不支持分页
解决方案:
选项1:拆分集合
typescript
// 不要使用一个庞大的"authors"集合
// 按活跃状态或字母顺序拆分

{
  name: 'active_author',
  label: 'Active Authors',
  path: 'content/authors/active',
  fields: [/* ... */]
}

{
  name: 'archived_author',
  label: 'Archived Authors',
  path: 'content/authors/archived',
  fields: [/* ... */]
}
选项2:使用带验证的字符串字段
typescript
// 替代引用字段
{
  type: 'string',
  name: 'authorId',
  label: 'Author ID',
  ui: {
    component: 'select',
    options: ['author-1', 'author-2', 'author-3']  // 精选列表
  }
}
选项3:自定义字段组件(高级)

9. ❌ Reference Field 503 Service Unavailable

10. ❌ 媒体管理器上传超时(幽灵上传)

Error:
  • Reference field dropdown times out with 503 error
  • Admin interface becomes unresponsive when loading reference field
Cause:
  • Too many items in referenced collection (100s or 1000s)
  • No pagination support for reference fields currently
Solutions:
Option 1: Split collections
typescript
// 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
typescript
// 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)

错误信息:
Upload failed
Error uploading image
原因:
  • 媒体管理器显示错误,但图片已在后台成功上传
  • UI超时未反映实际上传状态
  • 删除操作也会出现类似问题(显示错误但删除已成功)
解决方案:
如果上传显示错误:
  1. 等待5-10秒
  2. 关闭并重新打开媒体管理器
  3. 重试前检查图片是否已上传
  4. 避免重复上传
状态:已知问题(高优先级) 来源GitHub Issue #6325

10. ❌ Media Manager Upload Timeouts (Ghost Uploads)

部署选项

TinaCloud(托管服务)- 推荐

Error Message:
Upload failed
Error uploading image
Cause:
  • Media Manager shows error but image uploads successfully in background
  • UI timeout doesn't reflect actual upload status
  • Similar issue occurs with deletion (error shown but deletion succeeds)
Solution:
If upload shows error:
  1. Wait 5-10 seconds
  2. Close and reopen Media Manager
  3. Check if image already uploaded before retrying
  4. Avoid duplicate upload attempts
Status: Known issue (high priority) Source: GitHub Issue #6325

设置步骤:
  1. https://app.tina.io注册账号
  2. 获取Client ID和只读Token
  3. 设置环境变量:
    NEXT_PUBLIC_TINA_CLIENT_ID
    ,
    TINA_TOKEN
  4. 部署到Vercel/Netlify/Cloudflare Pages
优点:零配置,免费额度(每月10000次请求)

Deployment Options

Node.js自托管

TinaCloud (Managed) - Recommended

Setup:
  1. Sign up at https://app.tina.io
  2. Get Client ID and Read Only Token
  3. Set env vars:
    NEXT_PUBLIC_TINA_CLIENT_ID
    ,
    TINA_TOKEN
  4. Deploy to Vercel/Netlify/Cloudflare Pages
Pros: Zero config, free tier (10k requests/month)

⚠️ 边缘运行时限制:自托管TinaCMS无法在边缘运行时环境(Cloudflare Workers、Vercel Edge Functions)中使用,因为
@tinacms/datalayer
@tinacms/graphql
依赖Node.js API。边缘部署请使用TinaCloud(托管服务)。
来源GitHub Issue #4363(标记为"wontfix")
⚠️ 自托管示例可能过时:TinaCMS仓库中的官方自托管示例已被团队确认“相当过时”。请始终参考最新文档,不要仅依赖示例仓库。
仅适用于Node.js环境(非边缘运行时):
bash
pnpm install @tinacms/datalayer tinacms-authjs
npx @tinacms/cli@latest init backend
示例(Node.js服务器,非Workers):
typescript
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运行时可用,边缘运行时不支持
const handler = TinaNodeBackend({
  authProvider: isLocal
    ? LocalBackendAuthProvider()
    : AuthJsBackendAuthProvider({
        authOptions: TinaAuthJSOptions({
          databaseClient,
          secret: process.env.NEXTAUTH_SECRET,
        }),
      }),
  databaseClient,
})
优点:完全可控,自托管 缺点:需要Node.js运行时(无法使用边缘计算)

Self-Hosted on Node.js

⚠️ 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/datalayer
and
@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.
For Node.js environments only (not edge runtime):
bash
pnpm install @tinacms/datalayer tinacms-authjs
npx @tinacms/cli@latest init backend
Example (Node.js server, not Workers):
typescript
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)