Tina
Tina is an open-source, Git-backed headless CMS that enables developers to
You are a full-stack developer specializing in modern web applications, adept at integrating headless CMS solutions that prioritize developer experience and Git-based content workflows. You leverage Tina CMS to empower content creators with an intuitive, on-site editing experience while keeping content version-controlled and code-driven. ## Key Points * **Optimize GraphQL Queries:** Fetch only the data your components need. Tina's GraphQL API is efficient, but over-fetching can still impact performance, especially for large content sets. * **Use Tina Cloud for Production:** For seamless authentication, remote media management, and a unified content experience across multiple editors, connect your local Tina instance to Tina Cloud. ## Quick Example ```bash # In your project's root directory npm install --save tinacms @tinacms/cli @tinacms/mdx @tinacms/client npm install --save-dev @types/node # If you're using TypeScript ``` ```bash npx tinacms init ```
skilldb get cms-services-skills/TinaFull skill: 252 linesTina CMS Integration
You are a full-stack developer specializing in modern web applications, adept at integrating headless CMS solutions that prioritize developer experience and Git-based content workflows. You leverage Tina CMS to empower content creators with an intuitive, on-site editing experience while keeping content version-controlled and code-driven.
Core Philosophy
Tina CMS adopts a unique approach by tightly coupling content with your application's code repository. It operates as a local development server, providing a GraphQL API for your content and an in-context editing UI that lives within your application. This "Git-backed" philosophy means your content is stored as Markdown, JSON, or MDX files directly in your Git repository, making it version-controlled, auditable, and deployable alongside your code.
This architecture offers significant advantages for teams that value robust developer workflows, local-first content creation, and a clear separation of content and presentation logic. Tina's GraphQL API allows you to query content efficiently, while its component-based editing ensures a highly customizable and intuitive authoring experience. It's an excellent choice for static sites, server-rendered applications, and any project where content needs to be managed and versioned like code.
Setup
To integrate Tina CMS, you'll install its packages, initialize your project, and configure your content schema. Tina typically runs as a local development server that watches your content files and provides a GraphQL API.
Install Tina packages
# In your project's root directory
npm install --save tinacms @tinacms/cli @tinacms/mdx @tinacms/client
npm install --save-dev @types/node # If you're using TypeScript
Initialize Tina in your project
Run the Tina CLI to set up the necessary files. This will create a tina/ directory with a basic configuration.
npx tinacms init
Configure your Tina schema
Edit tina/config.ts to define your content collections and fields. This TypeScript file is where you model your content structure.
// tina/config.ts
import { defineConfig } from "tinacms";
const config = defineConfig({
branch: "main", // or your default branch
clientId: process.env.NEXT_PUBLIC_TINA_CLIENT_ID, // Your Tina Cloud Client ID
token: process.env.TINA_TOKEN, // Your Tina Cloud Token
build: {
outputFolder: "admin",
publicFolder: "public",
},
media: {
tina: {
mediaRoot: "uploads",
publicFolder: "public",
},
},
schema: {
collections: [
{
name: "post",
label: "Blog Posts",
path: "content/posts", // Where content files will live
fields: [
{
type: "string",
name: "title",
label: "Title",
isBody: false,
required: true,
},
{
type: "datetime",
name: "date",
label: "Date",
required: true,
ui: {
component: "date",
},
},
{
type: "string",
name: "author",
label: "Author",
required: true,
},
{
type: "rich-text", // For Markdown/MDX content
name: "body",
label: "Body",
isBody: true,
},
],
},
// Add more collections for pages, authors, etc.
],
},
});
export default config;
Start the Tina development server
npx tinacms dev
This command starts a local server at http://localhost:4001/graphql for your content API and prepares the Tina admin for your application.
Key Techniques
1. Querying Content with GraphQL
Tina generates a GraphQL API based on your schema. You'll use this API to fetch content for your application. For client-side queries with editing capabilities, use the useTina hook. For static or server-side queries, use the client.queries method.
// pages/blog/[slug].tsx (Next.js example)
import { useTina } from 'tinacms/dist/react';
import { client } from '../../.tina/__generated__/client'; // Auto-generated client
export default function BlogPost(props) {
// `data` will be editable in Tina's visual editor
const { data } = useTina({
query: props.query,
variables: props.variables,
data: props.data,
});
const post = data.post;
return (
<article>
<h1>{post.title}</h1>
<p>By {post.author} on {new Date(post.date).toLocaleDateString()}</p>
{/* Render rich-text content */}
<div dangerouslySetInnerHTML={{ __html: post.body.html }} />
</article>
);
}
export const getStaticPaths = async () => {
const { data } = await client.queries.postConnection();
const paths = data.postConnection.edges.map((edge) => ({
params: { slug: edge.node._sys.filename },
}));
return {
paths,
fallback: "blocking",
};
};
export const getStaticProps = async ({ params }) => {
const { data, query, variables } = await client.queries.post({
relativePath: `${params.slug}.md`,
});
return {
props: {
data,
query,
variables,
},
};
};
2. Enabling the Visual Editing UI
To enable in-context editing, wrap your application with TinaCMS and integrate the useTina hook. When the Tina development server is running, navigating to a page with useTina will activate the editing sidebar.
// pages/_app.tsx (Next.js example)
import { TinaCMS } from 'tinacms';
import { TinaEditProvider } from 'tinacms/dist/edit-state';
import dynamic from 'next/dynamic';
const TinaCMSWrapper = dynamic(() => import('../components/TinaCMSWrapper'), { ssr: false });
function MyApp({ Component, pageProps }) {
return (
<TinaEditProvider editMode={pageProps.draft}>
<Component {...pageProps} />
<TinaCMSWrapper {...pageProps} />
</TinaEditProvider>
);
}
export default MyApp;
// components/TinaCMSWrapper.tsx
// This component conditionally renders Tina's UI and should be dynamically imported
import React from 'react';
import { useCMS } from 'tinacms';
import { client } from '../.tina/__generated__/client'; // Auto-generated client
interface TinaCMSWrapperProps {
// Add any props your Tina client needs, e.g., branches
}
const TinaCMSWrapper: React.FC<TinaCMSWrapperProps> = (props) => {
const cms = useCMS();
// Ensure the client is initialized only once and available to Tina
if (!cms.api.tina) {
cms.api.tina = client;
}
return null; // Tina's UI renders globally, this component just ensures it's enabled
};
export default TinaCMSWrapper;
3. Creating and Managing Content Files
Tina automatically creates and updates content files (e.g., Markdown, MDX, JSON) in your Git repository based on your schema definitions. When content is edited via the visual UI, Tina saves these changes directly to your local files, ready for you to commit and push.
For example, when an editor creates a new blog post via the Tina UI, a new file like content/posts/my-new-post.md will be generated with the specified frontmatter and body.
---
title: My New Post
date: "2023-10-27T10:00:00.000Z"
author: Jane Doe
---
This is the **body** of my new post, written in Markdown.
You can use _rich text_ features here.
Best Practices
- Version Control Your Content: Always commit and push content changes to your Git repository regularly. Tina's strength lies in its Git-backed nature, ensuring content history and collaboration.
- Design a Clear Schema: Invest time in designing your
tina/config.tsschema. Use meaningful names, appropriate field types, and consider how editors will interact with the content. A well-structured schema leads to a better editing experience. - Local-First Development: Embrace Tina's local development workflow. Encourage content creators to pull the latest changes, run
npx tinacms dev, make edits, and then commit/push. This keeps content and code in sync. - Leverage Rich Text (MDX): For complex content blocks, use the
rich-textfield type. Tina supports Markdown, MDX components, and custom components within the editor, offering powerful flexibility. - Optimize GraphQL Queries: Fetch only the data your components need. Tina's GraphQL API is efficient, but over-fetching can still impact performance, especially for large content sets.
- Integrate with CI/CD: Set up your CI/CD pipeline to build and deploy your application whenever content changes are pushed to your main branch, ensuring your live site reflects the latest content.
- Use Tina Cloud for Production: For seamless authentication, remote media management, and a unified content experience across multiple editors, connect your local Tina instance to Tina Cloud.
Anti-Patterns
- Ignoring the Git Backend. Forgetting to commit and push content changes from your local repository. This leads to lost work and out-of-sync content across environments. Always treat content files as part of your codebase.
- Directly Manipulating
datafromuseTinafor Non-Content. Thedataobject fromuseTinais primarily for rendering and enabling content editing. Avoid using it for application state or arbitrary data mutations; instead, use standard React state management. - Over-Reliance on UI for Schema Changes. While Tina's UI is for content, your schema (
tina/config.ts) is code. Don't expect to define new content types or fields solely through the UI; always update yourconfig.tsfile. - Not Using
useTinafor Editable Content. If you fetch content but don't use theuseTinahook in your component, Tina's visual editing capabilities for that content will not be enabled. Ensure you passquery,variables, anddatatouseTinawhere editing is desired. - Hardcoding Content Paths. Relying on fixed file paths instead of using Tina's dynamic path generation and
_sys.filenamefor slugs. This makes content less flexible and harder to manage as your project scales.
Install this skill directly: skilldb add cms-services-skills
Related Skills
Builder Io
Builder.io is a Visual Headless CMS and API that empowers developers to integrate
Caisy
caisy is a headless CMS designed for speed and scalability, empowering developers
Contentful
Build with Contentful for headless content management. Use this skill when the
Cosmic
Integrate Cosmic as your headless content management system, providing
Directus
Build with Directus for database-first content management. Use this skill
Ghost
Integrate Ghost as a powerful headless CMS or a full-featured publishing platform.