Tina CMS: Rapid Integration and Easy Usage
In 2024, if you're considering creating a blog, there are several frameworks and tools that allow you to do so, with my favorites being Astro and Next.js. In both cases, there are various free templates available that you can utilize to save time. For easy creation and componentization, it's very common to develop the entire blog content using .md or mdx files.
Once you've completed the aforementioned steps, you might wonder if you could integrate a CMS easily and efficiently. In this case, I propose that you use Tina.
What is TinaCMS?
TinaCMS is an open-source Content Management System (CMS) that seamlessly integrates with your Markdown workflow.
The CMS Frontend
- TinaCMS provides an intuitive CMS interface for your editors. For sites using React, TinaCMS supports "Visual Editing" to allow content editors to see real-time changes.
For the most part, TinaCMS is framework-agnostic. Unless you're using "visual editing", the setup is mostly the same regardless of the site's framework.
We also have some guides tailored for some popular frameworks:
To initialize TinaCMS, run the following command:
npx @tinacms/cli@latest init
This will prompt you with a few setup questions. When prompted for the "public assets directory", refer to our list of frameworks for assistance.
Updating Your Build Scripts
Depending on your framework, tina init may try to update your package.json scripts:
"scripts": {
"dev": "tinacms dev -c \"next dev\"",
"build": "tinacms build && next build",
"start": "tinacms build && next start"
}
Replace <your-dev-process> with your site's custom dev command.
With TinaCMS running, navigate to http://localhost:3000/admin/index.html.

Content Modeling with TinaCMS
The Tina schema defines the shape of your content. Tina uses a "content-modeling as code" approach, which offers several benefits compared to modeling through a UI:
- The schema is version-controlled.
- Mutating the schema is easy, as you can test out changes locally or in a branch.
- Developers can extend the schema in interesting ways (custom validation, custom UI fields, etc.).
The content model and all configuration code are defined in a file called tina/config.ts,js,tsx:
// tina/config.{ts,js,tsx}
import { defineConfig } from 'tinacms'
export default defineConfig({
// ...
schema: {
collections: [
{
label: 'Blog Posts',
name: 'post',
path: 'content/posts',
fields: [
{
type: 'string',
label: 'Title',
name: 'title',
},
{
type: 'string',
label: 'Post Body',
name: 'body',
isBody: true,
},
],
},
],
},
})
Defining "Collections"
Each item in your collections array represents its own entity. In the above example, we defined a post collection and set its path as content/posts, which maps to a directory in our site's repository. Each collection contains an array of fields, each with a defined type.


