Comparison · for developers

Primo vs TinaCMS.

TinaCMS is the closest thing to Primo there is — both treat your files as the source of truth, both let editors click on the rendered page, both are happy to have an AI agent in the repo. If you’re choosing between them, you’re already past “should the CMS own my content” and onto the architecture. So this page is about one specific difference: what sits between your files and the editor. With Tina, it’s a GraphQL data layer and per-field instrumentation. With Primo, there’s nothing between them at all.

The short version
Pick TinaCMS if…

…you’re in React/Next.js today and won’t move, you want a markdown/MDX-first content model, or you want a mature hosted backend (TinaCloud) with media + git handling solved for you. Tina meets you where most of the JS ecosystem already lives.

Pick Primo if…

…you want the editor and the renderer to read the exact same source with no GraphQL layer to sync and no useTina to wire per field — and you’re building in (or willing to build in) Svelte. Your agent edits the block as code; your client edits the same block on the page.

Where they actually differ

TinaCMS
Primo
Source of truth
Files in your git repo
Files in your git repo
Visual on-page editing
Click-to-edit via contextual editing
Click-to-edit on the rendered page
Data layer between files & app
~ GraphQL layer (TinaCloud) the app queries
None — editor & renderer read files directly
Per-field wiring
~ useTina instrumentation to make fields editable
Editor generated from the field schema
Framework
React / Next.js (and others)
~ Svelte today; SvelteKit integrate coming
Backend
~ TinaCloud, or self-hosted data layer
Self-host (SQLite via PocketBase), MIT
License
Open source (Apache-2.0)
Open source (MIT)
Where TinaCMS genuinely wins

It meets the ecosystem where it already is.

This is the honest part, and it matters: the overwhelming majority of the JS frontend world is React, and Tina is a first-class citizen there. If your production app is Next.js, Tina drops in without asking you to change frameworks. Primo can't say that today — its blocks are Svelte.

Tina's content model is also markdown/MDX-first, which is exactly right for docs and blog-shaped content, and its AI/agent story is strong precisely because markdown files are so legible to a model. And TinaCloud is a real, maintained backend: it handles the git plumbing, media, and editorial workflow so you don't have to stand up infrastructure. For a lot of teams, "the hosted thing just works" is the correct trade.

The one architectural difference

Tina indexes files into a data layer. Primo doesn’t.

Here's the mechanism, stated fairly. Tina takes your files and indexes them into a GraphQL data layer (TinaCloud, or a self-hosted equivalent). Your app then queries that layer for content, and to make a field editable on the page you wrap its data in useTina so the editor knows which query result maps to which field. It's a clean design and it's why Tina works across many frameworks — GraphQL is the neutral interface in the middle.

But it is a middle. There's a layer to keep in sync, a query language to learn, and per-field instrumentation to maintain. Add a field to a component and you're not done until you've also threaded it through the query and the useTina binding.

Primo removes the middle entirely. A block is a Svelte component plus a fields.yaml next to it. The editor generates its UI from that field schema, and the renderer reads the same files. There's no GraphQL layer to query and no per-field wiring to add — declare the field in the schema and it's editable. That's the verified claim worth weighing: the block your agent edits as code and the page your client edits are the same files, and the editor is generated from the block's field schema, with no glue code.

What it means day to day

Adding a field, in both tools.

In Tina: edit the component, update the GraphQL query/schema, and add the useTina binding so the field becomes editable. Three places, kept consistent.

In Primo: add the field to fields.yaml and reference it in the component with a data-key. The editor picks it up from the schema — there's no query to update because nothing queries a data layer. One place, plus the markup that was going to render it anyway.

Neither is hard. But across a real site with dozens of blocks and an agent making changes all day, "one source, no sync step" is a meaningfully smaller surface to keep correct.

The honest catch

Today, Primo means Svelte.

The flip side of "no neutral data layer" is that Primo is tied to Svelte's compile-time model — that's what lets blocks be just files the editor and renderer both read directly. So if you're committed to React, Tina is the pragmatic choice right now and we won't pretend otherwise.

What's on Primo's roadmap is primo integrate <framework> — layering Primo's content + editor onto an existing SvelteKit app (Astro next, Next.js aspirational), where your production components stay in the framework. The blocks themselves stay Svelte. If that's a dealbreaker, it's a real one.

Questions developers ask

Is TinaCMS's GraphQL data layer a bad thing?

No — it’s a deliberate, well-built design, and it’s the reason Tina works across React, Next, and other frameworks. The point isn’t that the data layer is wrong; it’s that it’s a layer — something to query, sync, and instrument per field with useTina. Primo makes a different trade: no neutral middle, so the editor and renderer read the same files directly, at the cost of being Svelte-only today.

Do both work with AI agents like Claude Code?

Yes. Both keep content as files in your repo, which is exactly what makes an agent effective — it edits real files, not an API. Tina’s markdown-first model is very agent-legible. Primo’s difference is that an agent editing a block’s code and a client editing that block on the page are touching the same files, with no data layer in between to fall out of sync.

Can I use Primo with React or Next.js like I can with Tina?

Not today. Primo’s blocks are Svelte, because Svelte’s compile-time approach is what lets a block be “just files” both the editor and renderer read directly. On the roadmap is primo integrate for layering Primo onto an existing SvelteKit app (Astro next, Next.js aspirational). If you need React now, TinaCMS is the honest pick.

What happens to my content if the company disappears?

Both are open source and file-backed, so you’re in good shape either way. With Primo specifically, content lives in SQLite (via PocketBase) and code in your repo; primo pull gives you a static export of both at any time, and it’s MIT-licensed. Tina is Apache-2.0 with a self-hostable data layer.

Build it with an agent. Hand it to a human.

One command to spin up a workspace. Point any agent at the repo, then hand your client the browser.

$ npx primo-cli init my-workspace
✓ workspace ready · server.yaml written

MIT · open source · free forever