Token导航 LogoToken导航TokenDH.com
前端设计敏感数据github未标认证来源可访问clear审计通过

tinacmstinacms 命令行

Agent Skill

用于辅助前端页面、组件、样式和交互逻辑的开发与维护。它适合让 Agent 生成或审查 React、Next.js、Vue、Tailwind、CSS 等相关代码,整理组件结构,或定位布局和性能问题。使用时需要结合项目现有设计系统、路由和构建方式,避免只生成孤立片段;涉及页面改动时,应配合本地预览和构建检查确认视觉效果。

总安装

618

周安装

25

GitHub Stars

14

下载量

194
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

3

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:tinacms(tinacms 命令行)
来源仓库:https://github.com/jackspace/claudeskillz
仓库路径:skills/tinacms
安装命令:
npx skills add https://github.com/jackspace/claudeskillz --skill tinacms
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/jackspace/claudeskillz --skill tinacms

简介

用于辅助前端页面、组件、样式和交互逻辑的开发与维护。

  • 适合生成或审查 React、Next.js、Vue、Tailwind、CSS 等相关代码。
  • 使用时需结合项目现有设计系统、路由和构建方式,避免孤立片段。
  • 涉及页面改动时应配合本地预览和构建检查确认视觉效果。
  • 安装前建议核验仓库维护状态及是否会触发文件读写。

SKILL.md

TinaCMS Skill

Complete skill for integrating TinaCMS into modern web applications.


What is TinaCMS?

TinaCMS is an open-source, Git-backed headless content management system (CMS) that enables developers and content creators to collaborate seamlessly on content-heavy websites.

Key Features

  1. Git-Backed Storage

- Content stored as Markdown, MDX, or JSON files in Git repository - Full version control and change history - No vendor lock-in - content lives in your repo

  1. Visual/Contextual Editing

- Side-by-side editing experience - Live preview of changes as you type - WYSIWYG-like editing for Markdown content

  1. Schema-Driven Content Modeling

- Define content structure in code (tina/config.ts) - Type-safe GraphQL API auto-generated from schema - Collections and fields system for organized content

  1. Flexible Deployment

- TinaCloud: Managed service (easiest, free tier available) - Self-Hosted: Cloudflare Workers, Vercel Functions, Netlify Functions, AWS Lambda - Multiple authentication options (Auth.js, custom, local dev)

  1. Framework Support

- Best: Next.js (App Router + Pages Router) - Good: React, Astro (experimental visual editing), Gatsby, Hugo, Jekyll, Remix, 11ty - Framework-Agnostic: Works with any framework (visual editing limited to React)

Current Versions

  • tinacms: 2.9.0 (September 2025)
  • @tinacms/cli: 1.11.0 (October 2025)
  • React Support: 19.x (>=18.3.1 <20.0.0)

When to Use This Skill

✅ Use TinaCMS When:

  1. Building Content-Heavy Sites

- Blogs and personal websites - Documentation sites - Marketing websites - Portfolio sites

  1. Non-Technical Editors Need Access

- Content teams without coding knowledge - Marketing teams managing pages - Authors writing blog posts

  1. Git-Based Workflow Desired

- Want content versioning through Git - Need content review through pull requests - Prefer content in repository with code

  1. Visual Editing Required

- Editors want to see changes live - WYSIWYG experience preferred - Side-by-side editing workflow

❌ Don't Use TinaCMS When:

  1. Real-Time Collaboration Needed

- Multiple users editing simultaneously (Google Docs-style) - Use Sanity, Contentful, or Firebase instead

  1. Highly Dynamic Data

- E-commerce product catalogs with frequent inventory changes - Real-time dashboards - Use traditional databases (D1, PostgreSQL) instead

  1. No Content Management Needed

- Application is data-driven, not content-driven - Hard-coded content is sufficient


Setup Patterns by Framework

Use the appropriate setup pattern based on your framework choice.

1. Next.js Setup (Recommended)

App Router (Next.js 13+)

Steps:

  1. Initialize TinaCMS: npx @tinacms/cli@latest init

- When prompted for public assets directory, enter public

  1. Update package.json scripts: {"scripts": {"dev": "tinacms dev -c \"next dev\"", "build": "tinacms build && next build", "start": "tinacms build && next start"}}
  2. Set environment variables: #.env.local NEXT_PUBLIC_TINA_CLIENT_ID=your_client_id TINA_TOKEN=your_read_only_token
  3. Start development server: npm run dev
  4. Access admin interface: http://localhost:3000/admin/index.html

Key Files Created:

  • tina/config.ts - Schema configuration
  • app/admin/[[...index]]/page.tsx - Admin UI route (if using App Router)

Template: See templates/nextjs/tina-config-app-router.ts


Pages Router (Next.js 12 and below)

Setup is identical, except admin route is:

  • pages/admin/[[...index]].tsx instead of app directory

Data Fetching Pattern:

// 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' }
}

Template: See templates/nextjs/tina-config-pages-router.ts


2. Vite + React Setup

Steps:

  1. Install dependencies: npm install react@^19 react-dom@^19 tinacms
  2. Initialize TinaCMS: npx @tinacms/cli@latest init

- Set public assets directory to public

  1. Update vite.config.ts: import {defineConfig} from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({plugins: [react()], server: {port: 3000 // TinaCMS default}})
  2. Update package.json scripts: {"scripts": {"dev": "tinacms dev -c \"vite\"", "build": "tinacms build && vite build", "preview": "vite preview"}}
  3. Create admin interface: Option A: Manual route (React Router) // src/pages/Admin.tsx import TinaCMS from 'tinacms' export default function Admin() {return <div id="tina-admin" />} Option B: Direct HTML <!-- public/admin/index.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>
  4. Use useTina hook for visual editing: 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>)}
  5. Set environment variables: #.env VITE_TINA_CLIENT_ID=your_client_id VITE_TINA_TOKEN=your_read_only_token

Template: See templates/vite-react/


3. Astro Setup

Steps:

  1. Use official starter (recommended): npx create-tina-app@latest --template tina-astro-starter Or initialize manually: npx @tinacms/cli@latest init
  2. Update package.json scripts: {"scripts": {"dev": "tinacms dev -c \"astro dev\"", "build": "tinacms build && astro build", "preview": "astro preview"}}
  3. Configure Astro: // astro.config.mjs import {defineConfig} from 'astro/config' import react from '@astro/react' export default defineConfig({integrations: [react()] // Required for Tina admin})
  4. Visual editing (experimental):

- Requires React components - Use client:tinaDirective for interactive editing - Full visual editing is experimental as of October 2025

  1. Set environment variables: #.env PUBLIC_TINA_CLIENT_ID=your_client_id TINA_TOKEN=your_read_only_token

Best For: Content-focused static sites, documentation, blogs

Template: See templates/astro/


4. Framework-Agnostic Setup

Applies to: Hugo, Jekyll, Eleventy, Gatsby, Remix, or any framework

Steps:

  1. Initialize TinaCMS: npx @tinacms/cli@latest init
  2. Manually configure build scripts: {"scripts": {"dev": "tinacms dev -c \"<your-dev-command>\"", "build": "tinacms build && <your-build-command>"}}
  3. Admin interface:

- Automatically created at http://localhost:<port>/admin/index.html - Port depends on your framework

  1. Data fetching:

- No visual editing (sidebar only) - Content edited through Git-backed interface - Changes saved directly to files

  1. Set environment variables: TINA_CLIENT_ID=your_client_id TINA_TOKEN=your_read_only_token

Limitations:

  • No visual editing (React-only feature)
  • Manual integration required
  • Sidebar-based editing only

Schema Modeling Best Practices

Define your content structure in tina/config.ts.

Basic Config Structure

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
    ],
  },
})

Collections

Collection = Content type + directory mapping

{
  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
}

Key Properties:

  • name: Internal identifier (alphanumeric + underscores only)
  • label: Human-readable name for admin interface
  • path: File path relative to project root
  • format: File extension (defaults to 'md')
  • fields: Content structure definition

Field Types Reference

TypeUse CaseExample
stringShort text (single line)Title, slug, author name
rich-textLong formatted contentBlog body, page content
numberNumeric valuesPrice, quantity, rating
datetimeDate/time valuesPublished date, event time
booleanTrue/false togglesDraft status, featured flag
imageImage uploadsHero image, thumbnail, avatar
referenceLink to another documentAuthor, category, related posts
objectNested fields groupSEO metadata, social links

Complete reference: See references/field-types-reference.md


Collection Templates

Blog Post Collection

{
  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}`
  }
}

Template: See templates/collections/blog-post.ts


Documentation Page Collection

{
  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}`
    }
  }
}

Template: See templates/collections/doc-page.ts


Author Collection (Reference Target)

{
  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'
        }
      ]
    }
  ]
}

Template: See templates/collections/author.ts


Landing Page Collection (Multiple Templates)

{
  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'
            }
          ]
        }
      ]
    }
  ]
}

When using templates: Documents must include _template field in frontmatter:

---
_template: landing
title: My Landing Page
---

Template: See templates/collections/landing-page.ts


Common Errors & Solutions

1. ❌ ESbuild Compilation Errors

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:

// ❌ 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


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

Error Message:

Error: Could not resolve "tinacms"

Causes:

  • Corrupted or incomplete installation
  • Version mismatch between dependencies
  • Missing peer dependencies

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:

  • 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)

3. ❌ Field Naming Constraints

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:

// ❌ 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


4. ❌ Docker Binding Issues

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:

# 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"

5. ❌ Missing _template Key Error

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)

{
  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' {} +

6. ❌ Path Mismatch Issues

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:

// 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

7. ❌ Build Script Ordering Problems

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:

{
  "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__/
  • Framework build needs these types to compile successfully
  • Running in wrong order causes type errors

8. ❌ Failed Loading TinaCMS Assets

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:

{
  "scripts": {
    "build": "tinacms build && next build"  // ✅ Always build
    // NOT: "build": "tinacms dev"          // ❌ Never dev in production
  }
}

For Subdirectory Deployments:

// tina/config.ts
export default defineConfig({
  build: {
    outputFolder: 'admin',
    publicFolder: 'public',
    basePath: 'your-subdirectory'  // ← Set if site not at domain root
  }
})

CI/CD Fix:

# GitHub Actions / Vercel / Netlify
- run: npx @tinacms/cli@latest build  # Always use build, not dev

9. ❌ Reference Field 503 Service Unavailable

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

// 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)


Deployment Patterns

Choose the deployment approach that fits your needs.

Option 1: TinaCloud (Managed) - Easiest ⭐

Best For: Quick setup, free tier, managed infrastructure

Steps:

  1. Sign up at https://app.tina.io
  2. Create project, get Client ID and Read Only Token
  3. Set environment variables: NEXT_PUBLIC_TINA_CLIENT_ID=your_client_id TINA_TOKEN=your_read_only_token
  4. Initialize backend: npx @tinacms/cli@latest init backend
  5. Deploy to hosting provider (Vercel, Netlify, Cloudflare Pages)
  6. Set up GitHub integration in Tina dashboard

Pros:

  • ✅ Zero backend configuration
  • ✅ Automatic GraphQL API
  • ✅ Built-in authentication
  • ✅ Git integration handled automatically
  • ✅ Free tier generous (10k monthly requests)

Cons:

  • ❌ Paid service beyond free tier
  • ❌ Vendor dependency (content still in Git though)

Reference: See references/deployment-guide.md#tinacloud


Option 2: Self-Hosted on Cloudflare Workers 🔥

Best For: Full control, Cloudflare ecosystem, edge deployment

Steps:

  1. Install dependencies: npm install @tinacms/datalayer tinacms-authjs
  2. Initialize backend: npx @tinacms/cli@latest init backend
  3. Create Workers endpoint: // 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)}}
  4. Update tina/config.ts: export default defineConfig({contentApiUrlOverride: '/api/tina/gql', // Your Workers endpoint //... rest of config})
  5. Configure 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"}}}}
  6. Deploy: npx wrangler deploy

Pros:

  • ✅ Full control over backend
  • ✅ Generous free tier (100k requests/day)
  • ✅ Global edge network (fast worldwide)
  • ✅ No vendor lock-in

Cons:

  • ❌ More setup complexity
  • ❌ Authentication configuration required
  • ❌ Cloudflare Workers knowledge needed

Complete Guide: See references/self-hosting-cloudflare.md

Template: See templates/cloudflare-worker-backend/


Option 3: Self-Hosted on Vercel Functions

Best For: Next.js projects, Vercel ecosystem

Steps:

  1. Install dependencies: npm install @tinacms/datalayer tinacms-authjs
  2. Create API route: // 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
  3. Create vercel.json rewrites: {"rewrites": [{"source": "/api/tina/:path*", "destination": "/api/tina/backend"}]}
  4. Update dev script: {"scripts": {"dev": "TINA_PUBLIC_IS_LOCAL=true tinacms dev -c \"next dev --port $PORT\""}}
  5. Set environment variables in Vercel dashboard: NEXTAUTH_SECRET=your-secret TINA_PUBLIC_IS_LOCAL=false
  6. Deploy: vercel deploy

Pros:

  • ✅ Native Next.js integration
  • ✅ Simple Vercel deployment
  • ✅ Serverless (scales automatically)

Cons:

  • ❌ Vercel-specific
  • ❌ Function limitations (10s timeout, 50MB size)

Reference: See references/deployment-guide.md#vercel


Option 4: Self-Hosted on Netlify Functions

Steps:

  1. Install dependencies: npm install express serverless-http @tinacms/datalayer tinacms-authjs
  2. Create function: // 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)
  3. Create netlify.toml: [functions] node_bundler = "esbuild" [[redirects]] from = "/api/tina/*" to = "/.netlify/functions/tina" status = 200 force = true
  4. Deploy: netlify deploy --prod

Reference: See references/deployment-guide.md#netlify


Authentication Setup

Option 1: Local Development (Default)

Use for: Local development, no production deployment

// tina/__generated__/databaseClient or backend config
const isLocal = process.env.TINA_PUBLIC_IS_LOCAL === 'true'

authProvider: isLocal ? LocalBackendAuthProvider() : /* ... */

Environment Variable:

TINA_PUBLIC_IS_LOCAL=true

Security: NO authentication - only use locally!


Option 2: Auth.js (Recommended for Self-Hosted)

Use for: Self-hosted with OAuth providers (GitHub, Discord, Google, etc.)

Install:

npm install next-auth tinacms-authjs

Configure:

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,
})

Supported Providers: GitHub, Discord, Google, Twitter, Facebook, Email, etc.

Reference: https://next-auth.js.org/providers/


Option 3: TinaCloud Auth (Managed)

Use for: TinaCloud hosted service

import { TinaCloudBackendAuthProvider } from '@tinacms/auth'

authProvider: TinaCloudBackendAuthProvider()

Setup:

  1. Sign up at https://app.tina.io
  2. Create project
  3. Manage users in dashboard
  4. Automatically handles authentication

Option 4: Custom Auth Provider

Use for: Existing auth system, custom requirements

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 Usage

TinaCMS automatically generates a type-safe GraphQL client.

Querying Data

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()

Self-Hosted:

import client from '../tina/__generated__/databaseClient'

// Same API as TinaCloud client
const post = await client.queries.post({
  relativePath: 'hello-world.md'
})

Visual Editing with useTina Hook

Next.js Example:

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
    }
  }
}

How It Works:

  • In production: useTina returns the initial data (no overhead)
  • In edit mode: useTina connects to GraphQL and updates in real-time
  • Changes appear immediately in preview

Additional Resources

Templates

  • templates/nextjs/ - Next.js App Router + Pages Router configs
  • templates/vite-react/ - Vite + React setup
  • templates/astro/ - Astro integration
  • templates/collections/ - Pre-built collection schemas
  • templates/cloudflare-worker-backend/ - Cloudflare Workers self-hosting

References

  • references/schema-patterns.md - Advanced schema modeling patterns
  • references/field-types-reference.md - Complete field type documentation
  • references/deployment-guide.md - Deployment guides for all platforms
  • references/self-hosting-cloudflare.md - Complete Cloudflare Workers guide
  • references/common-errors.md - Extended error troubleshooting
  • references/migration-guide.md - Migrating from Forestry.io

Scripts

  • scripts/init-nextjs.sh - Automated Next.js setup
  • scripts/init-vite-react.sh - Automated Vite + React setup
  • scripts/init-astro.sh - Automated Astro setup
  • scripts/check-versions.sh - Verify package versions

Official Documentation


Token Efficiency

Estimated Savings: 65-70% (10,900 tokens saved)

Without Skill (~16,000 tokens):

  • Initial research and exploration: 3,000 tokens
  • Framework setup trial & error: 2,500 tokens
  • Schema modeling attempts: 2,000 tokens
  • Error troubleshooting: 4,000 tokens
  • Deployment configuration: 2,500 tokens
  • Authentication setup: 2,000 tokens

With Skill (~5,100 tokens):

  • Skill discovery: 100 tokens
  • Skill loading (SKILL.md): 3,000 tokens
  • Template selection: 500 tokens
  • Minor project-specific adjustments: 1,500 tokens

Errors Prevented

This skill prevents 9 common errors (100% prevention rate):

  1. ✅ ESbuild compilation errors (import issues)
  2. ✅ Module resolution problems
  3. ✅ Field naming constraint violations
  4. ✅ Docker binding issues
  5. ✅ Missing _template key errors
  6. ✅ Path mismatch problems
  7. ✅ Build script ordering failures
  8. ✅ Asset loading errors in production
  9. ✅ Reference field 503 timeouts

Quick Start Examples

Example 1: Blog with 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

Example 2: Documentation Site with 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

Example 3: Self-Hosted on 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

Production Examples


Support

Issues? Check references/common-errors.md first

Still Stuck?


Last Updated: 2025-10-24 Skill Version: 1.0.0 TinaCMS Version: 2.9.0 CLI Version: 1.11.0

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

能力 5

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Claude Code

29.6%
按下载量换算57

windsurf

23.05%
按下载量换算45

OpenCode

16.96%
按下载量换算33

Codex

11.08%
按下载量换算21

Antigravity

8.23%
按下载量换算16

Gemini CLI

3.35%
按下载量换算6

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

来源信息

继续浏览同类 Skills