Open-source project
tinacms/tinacms avatar
tinacms/tinacms

TinaCMS: Git-backed editing for Markdown and MDX sites

TinaCMS is the leading open-source headless CMS that supports Markdown and Visual Editing. Your content is stored in your own GitHub repo.

13,807 stars758 forksTypeScriptApache-2.0

At a glance

What is it?
TinaCMS is an Apache-2.0 headless CMS that keeps Markdown, MDX, JSON and YAML in your own GitHub repo and layers a GraphQL API and optional visual editing on top. It suits teams whose content already lives in files; it is the wrong tool for anyone who wants a database-first CMS with no build step.
Who is it for?
Adopt TinaCMS if your content is already Markdown, MDX, JSON or YAML in a Git repository and you want non-technical editors to work in a preview rather than a terminal. Do not adopt it if you need a database-backed CMS that runs without a build step, or if you cannot accept a hosted service or self-hosted auth layer between editors and your repo.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem TinaCMS solves: editing files without giving up files

Most content teams end up in one of two places. Either the content lives in a database behind an admin panel, and developers lose the ability to review copy in a pull request, or the content lives as Markdown in a repository, and writers are asked to edit prose inside a code editor. TinaCMS takes the second arrangement and adds an editing layer on top of it. The README describes it as a headless content management system with support for Markdown, MDX, JSON, YAML and more, and states that content is stored in your own GitHub repo. That storage decision is the whole point: the files stay the source of truth, so diffs, branches, review and rollback are Git operations rather than CMS features.

The audience follows from that. It is for teams that already have a statically generated or server-side rendered site and want less-technical people to edit it. The README says the live preview is optional and opt-in and exists to make editing Markdown files intuitive for less-technical people. If nobody outside the engineering team ever touches the content, the editing layer is overhead you are paying for without a user.

How the GraphQL layer and visual editing actually fit together

TinaCMS does not read your Markdown directory at runtime and hand it to a template. It generates a schema from your content, and that schema is served through a GraphQL API. The README gives the shape of the query model directly: a nested path such as post.author.firstName resolves a field on a referenced document. That means references between documents are first-class, and the API, not the file system, is what your pages query.

The second layer is the editor. The README describes a live preview that is opt-in. When it is enabled, an editor changes a field in a browser and sees the rendered page update, and the change is written back to the Markdown file. Because the write path ends in a Git commit, the editing session and the repository history are the same artifact. The practical consequence is that every content change is a commit, which is good for auditability and awkward for anything you would rather not put through a branch, such as a hundred small edits in an afternoon.

The repository is a pnpm and Turborepo monorepo. The root package.json sets workspaces across packages/@tinacms/*, examples/*/* and packages/[^@]*, with build, test and type tasks routed through turbo. Releases are cut with changesets, which is why the recent release list carries independent version numbers such as [email protected] alongside [email protected] and [email protected]. Those packages version separately, so an upgrade is rarely a single number bump.

Installing TinaCMS and getting to a first edit

The README's getting-started instruction is a single scaffold command. It creates a starter site you can run locally. The README does not state which frameworks the scaffold offers, so treat the choice as something you see when the command runs rather than something documented here.

bash
npx create-tina-app@latest

If you would rather look before you install, the README points to a demo site on TinaCloud at app.tina.io/quickstart. That is a hosted environment, not a local one, so it shows the editing experience without showing you the repository wiring.

The repository itself expects specific toolchain versions. The root package.json declares an engines field, and that is the constraint to check before you file a bug against your own setup.

json
{
  "engines": {
    "node": "22.x || 24.x",
    "npm": "11.x",
    "pnpm": ">=11"
  }
}

Working inside the monorepo rather than against a scaffolded app is a different job. The root scripts build packages through Turborepo and run the test suites the same way, so a contributor checks out the repository and installs with pnpm before anything else. The README does not document install steps for the monorepo itself; the package.json scripts are the only source for how the pieces are built and tested.

bash
pnpm install
pnpm run build
pnpm test

The first two commands build every package under packages/** through turbo, and the third runs the test task over the same filter. Expect the build to take a while on a cold cache because it covers the whole workspace, not just the package you care about.

Where TinaCMS stops being the right answer

The Git-backed model is a constraint, not a detail. If your content lives in a database, or your editors need to publish without a deploy or a rebuild in the loop, TinaCMS is the wrong shape. A statically generated site has to regenerate for a content change to appear, and the README's framing of statically generated and server-side rendered pages does not remove that step.

The editing backend is the second constraint, and the documentation is thinner here than the marketing. Visual editing is not a purely client-side feature: something has to authenticate the editor and write commits back to the repository. The repository ships packages that suggest the shape of that problem, including tinacms-authjs and next-tinacms-s3, but the README does not walk through self-hosting the backend. If your requirement is that no third-party service sits between your editors and your repository, you are signing up to assemble that path yourself, and the README will not be your guide.

Scale is the third. A repository full of Markdown is a fine store for a few thousand documents and a poor one for a catalogue that changes continuously across many editors. Every edit is a commit, and merge behaviour under concurrent editing is Git's, not the CMS's.

TinaCMS compared with Decap CMS and Keystatic

The closest comparison is Decap CMS, the Git-based editor formerly known as Netlify CMS. Both keep content as files in your repository and both put an editing UI in front of it. The difference is the query layer. Decap exposes your content through its own config-driven collections and leaves the reading side to your static site generator. TinaCMS generates a schema and serves a GraphQL API over it, so pages query fields and references through that API, which is what makes a nested path like post.author.firstName work. If you want the CMS to stay out of your data-fetching code, Decap is the lighter arrangement. If you want typed, reference-aware queries over the same files, TinaCMS is doing more work for you.

Keystatic is the other comparison worth making. It is also Git-backed and file-based, and the README here does not compare the two, so the honest difference to state is architectural rather than a scorecard: TinaCMS separates the schema and query layer from the editing UI and ships a hosted service alongside the open-source packages, while a file-based CMS that keeps everything in the application's own config avoids that extra moving part. The trade is convenience against surface area.

Against database-first systems such as Strapi, Payload or Sanity, the split is simpler. Those store content in their own datastore and give you an admin panel that works independently of your build. TinaCMS keeps your files authoritative and makes your repository the audit log. Pick based on where you want the source of truth to live, not on feature checklists.

Licence, maintenance and the real cost of upgrading

The repository is Apache-2.0, which permits commercial use and modification and includes an explicit patent grant. That is the licence on the code in this repository. It does not automatically cover a hosted service you connect the code to, and it says nothing about the terms of any paid tier. Read those separately rather than assuming the Apache-2.0 file settles the question.

Maintenance is visible in the release cadence. The most recent push to the default branch was on 2026-08-24, the same date as the [email protected] release, and that release sits alongside [email protected] and [email protected] from the same day. The repository is not archived.

The upgrade cost comes from the workspace layout. Because the packages version independently and the root build routes through turbo with changesets driving versions, a TinaCMS upgrade can move more than one package at a time, and the auth and storage adapters carry their own major numbers. The root package.json also provides diff-tina-lock and update-tina-lock scripts that run across the workspace, which tells you the maintainers expect lockfile churn to be a routine part of upgrading rather than an exception. Budget for reading a changeset, not for bumping one dependency.

Editorial conclusion

Adopt TinaCMS if your content is already Markdown, MDX, JSON or YAML in a Git repository and you want non-technical editors to work in a preview rather than a terminal. Do not adopt it if you need a database-backed CMS that runs without a build step, or if you cannot accept a hosted service or self-hosted auth layer between editors and your repo. Before committing, verify your Node and package manager versions against the engines field, confirm whether your deployment target supports the server-side pieces the visual editor needs, and decide where the editing backend will run.

Frequently asked questions

Is TinaCMS free?

The code in the repository is licensed under Apache-2.0, which permits commercial use and modification. The README also points to a hosted demo on TinaCloud, and the terms of that service are separate from the licence on the repository.

What is Tina Cloud?

The README links to a demo site at app.tina.io/quickstart and describes it as a TinaCloud quickstart, but it does not explain what the service includes or how it relates to self-hosting the editing backend. Treat it as a hosted way to try the editing experience.

how to install tinacms

The README's getting-started section gives one command, npx create-tina-app@latest, which scaffolds a starter site you can run locally. The repository's own engines field requires Node 22.x or 24.x, npm 11.x and pnpm 11 or later.

what is tinacms

TinaCMS is a headless content management system that supports Markdown, MDX, JSON and YAML, stores your content in your own GitHub repo, and exposes it through a GraphQL API. A live preview is available as an opt-in feature for less-technical editors.

how to use tinacms

You scaffold a starter with npx create-tina-app@latest or try the hosted demo, then query your content through the generated GraphQL API, where fields and references resolve as nested paths such as post.author.firstName. Visual editing is opt-in rather than on by default.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tinacms-tinacms.svg)](https://hysenlabs.com/projects/tinacms-tinacms)