EmDash CMS vs Tina CMS: Which One Should You Choose?

EmDash CMS vs Tina CMS: Which One Should You Choose?

TinaCMS makes a genuinely unusual architectural choice for a modern CMS: no database. Content lives as Markdown, MDX, or JSON files directly in your Git repository, versioned the same way your code is. EmDash takes the more conventional path — structured content in a real database, with each content type getting its own table. This comparison is really about whether Git-as-database is a feature or a constraint for your project.

Table of Contents
  1. Quick Answer
  2. Git and Markdown as the Database
  3. Visual, In-Context Editing
  4. Pricing
  5. A Notable Ownership Change
  6. Content Scale Considerations
  7. Plugin and Extension Security
  8. Where TinaCMS Pulls Ahead
  9. Where EmDash Pulls Ahead
  10. Frequently Asked Questions
  11. Is Git-based content storage a good idea for a large site?
  12. Does EmDash have visual, in-context editing like TinaCMS?
  13. Does TinaCMS's acquisition by SSW affect its open-source availability?
  14. Can TinaCMS and EmDash be used for the same kind of site?
  15. The Bottom Line
  16. Sources

Quick Answer

TinaCMS is the stronger choice if your content genuinely belongs in Git — documentation sites, developer blogs, small marketing sites where version-controlled Markdown is a natural fit — and you want visual, in-context editing on top of that. EmDash is the stronger choice if you need structured, relational content that doesn't map cleanly to files, or content volume large enough that Git-based storage becomes unwieldy.

Git and Markdown as the Database

TinaCMS is the leading open-source headless CMS that supports Markdown and Visual Editing — a developer-friendly, open-source CMS powered by Git and Markdown with no databases.

That's a deliberate simplicity: no database to provision, back up, or migrate — your content history is your Git history, and a content rollback is a Git revert. For documentation sites, technical blogs, and smaller marketing sites, that's a genuinely elegant fit, especially for teams already comfortable with Git workflows. EmDash's structured, typed content in a real database is a better fit once you need relational data (categories linking to many posts, complex taxonomies, user-generated content like comments) that doesn't map naturally onto individual files in a repo.

Read also:

Visual, In-Context Editing

TinaCMS's other headline feature is its visual editor: editors click directly on live page elements to edit them in a sidebar, with real-time preview updates as they type — genuinely reducing the gap between "editing content" and "seeing the actual page." EmDash's admin panel is more conventional and form-based; there's no live, in-context visual editing layer. If a marketer or non-technical editor needs to see exactly what they're publishing as they build it, TinaCMS's visual editor is a real, tangible advantage EmDash doesn't currently match.

Pricing

TinaCMS's 2026 tiers: a free plan for 2 users with the full feature set and unlimited content, a Team plan at $29/month (up to 5 users, role-based access, priority support), and a Business plan at $149/month (unlimited users, SSO, custom roles, SLAs). The free, self-hosted option covers small teams well; TinaCloud (the managed backend) is what the paid tiers are really for. EmDash's self-hosted model has no per-seat pricing at any team size — cost is infrastructure only, regardless of how many editors you have.

A Notable Ownership Change

Worth knowing if you're evaluating TinaCMS for a long-term project: it was acquired by SSW (Superior Software for Windows), an Australian enterprise software company, in May 2024. The open-source core remains available, and development has continued (version 3 shipped a move to ESM and improvements to its editorial workflow), but an acquisition is always worth factoring into a long-term platform bet the same way we've flagged Payload's recent acquisition by Figma elsewhere in this series.

Content Scale Considerations

Git-based content storage genuinely works well up to a point — but a site with thousands of entries, complex relational queries, or high-frequency content changes from many simultaneous editors will start to feel the limits of files-in-a-repo as a content model, both in Git repository performance and in the mental overhead of reasoning about deeply nested file structures. EmDash's database-backed model doesn't have an equivalent ceiling; structured tables scale to large content volumes without the same file-count or repository-size considerations.

Plugin and Extension Security

TinaCMS's extensibility is mostly scoped through its TypeScript schema and React-based visual editor customization, running within your own codebase rather than through a separate plugin marketplace — which sidesteps a lot of third-party plugin-security concerns simply by not having that surface area. EmDash's sandboxed, permission-scoped plugin architecture addresses a different scenario: a genuine, installable plugin ecosystem that needs isolation because it's not all first-party code you wrote yourself.

Where TinaCMS Pulls Ahead

  • A genuinely differentiated, real-time visual editor for in-context Markdown editing.
  • Git-native storage — no database to provision, back up, or migrate, with content history as Git history.
  • A natural fit for documentation sites and developer-facing content specifically.
  • No per-seat pricing on the free, self-hosted tier for small teams.

Where EmDash Pulls Ahead

  • A structured, database-backed content model that scales past what Git-as-database comfortably handles.
  • Sandboxed, permission-scoped plugin security for a genuine third-party extension ecosystem.
  • Better fit for relational content — categories, taxonomies, comments — that doesn't map cleanly to individual files.
  • No recent ownership change to factor into a long-term platform decision.

Frequently Asked Questions

Is Git-based content storage a good idea for a large site?

For a large volume of frequently-changing, highly relational content, it becomes less practical — repository size, merge complexity, and the lack of native relational queries all become real friction points. It's a much better fit for documentation and smaller content sets.

Does EmDash have visual, in-context editing like TinaCMS?

No — that's TinaCMS's clearest differentiator. EmDash's admin experience is form-based rather than a live visual canvas, similar to the gap we've noted against Storyblok elsewhere in this series.

Does TinaCMS's acquisition by SSW affect its open-source availability?

Not so far — the open-source core has continued to receive updates, including a significant version 3 release. As with any acquisition, it's worth monitoring for future direction changes, but there's no indication of the open-source project being discontinued.

Can TinaCMS and EmDash be used for the same kind of site?

For a documentation site, developer blog, or small marketing site with Git-comfortable editors, yes, either could work, with TinaCMS's visual editing as the deciding factor. For a larger, more relationally complex site, EmDash's database-backed model is the better architectural fit.

The Bottom Line

If your content is naturally suited to Git and Markdown, and real-time visual editing matters to your team, TinaCMS's git-native architecture and editor are a strong, focused choice. If you need structured, relational content that scales past what files-in-a-repo comfortably handle, EmDash's database-backed model is the better long-term foundation. See how it compares to another Git-based CMS approach for more on this category generally.

Sources

Share

Comments

Write a comment

Related Articles

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

July 16, 2026

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

July 16, 2026

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

July 16, 2026

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

TL;DR — A custom session-cookie login flow appeared to succeed on localhost (the OTP verified, the response looked fine) but every subsequent request to a login-gated page treated the visitor as logged out. Identical code worked fine on the live HTTPS site. The cookie's Secure attribute was hardcoded to true — and per the cookie spec, browsers never store or send a Secure cookie over a plain, non-HTTPS connection.

Table of Contents
  1. Diagnostic
  2. Root cause
  3. Fix
  4. Lessons learned

Diagnostic

Check the actual Set-Cookie response header and the browser's own cookie storage panel — on localhost over http://, the cookie is sent by the server but never actually stored by the browser.

Root cause

// before -- assumes the app is always served over HTTPS
setCookie("session", token, { secure: true, httpOnly: true });
emdashkits.com

A cookie config that quietly assumes "we're always on HTTPS" breaks the instant you test over plain HTTP, which local dev servers commonly are.

Read also:

Fix

// after -- derive secure from the actual request protocol
const isHttps = request.url.startsWith("https://");
setCookie("session", token, { secure: isHttps, httpOnly: true });
emdashkits.com

Lessons learned

  • Any Secure-flagged cookie needs to key off the real request scheme, not an assumption baked in once at cookie-creation time.
  • "Works in production, silently fails in local dev" is a strong signal to check cookie flags before anything else in an auth flow.
  • Check other cookies in the same codebase for the same hardcoded assumption — if one cookie has this bug, sibling cookies set the same way are worth auditing too.
Share
Previous Article

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Comments

Write a comment

Related Articles

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

July 16, 2026

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

July 16, 2026

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)

July 16, 2026

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

TL;DR — GA4's gtag.js snippet was installed correctly, the page loaded with no visible JavaScript error, and GA4's real-time report still showed zero activity. The CMS's default Content-Security-Policy had no allowance for analytics domains and no config option to add one — so every request to Google's tracking endpoints was blocked at the browser level before it could fail loudly.

Table of Contents
  1. Diagnostic
  2. Root cause
  3. Lessons learned

Diagnostic

Check the browser's dedicated CSP violation reporting, not the regular console error list — CSP blocks are reported through their own channel, not thrown as normal script errors, so "no console errors" doesn't mean nothing was blocked.

Root cause

The CSP's script-src and connect-src directives had no entry for googletagmanager.com or google-analytics.com, and the CMS exposed no configuration surface to add one — the only way in was patching the CSP directives directly.

// patch-package: add analytics domains to the existing CSP directives
scriptSrc.push("https://www.googletagmanager.com");
connectSrc.push("https://www.google-analytics.com", "https://www.googletagmanager.com");
emdashkits.com
Read also:

Lessons learned

  • "No console errors" is not proof nothing was blocked — CSP violations live in their own reporting surface and are easy to miss if you're only scanning for red error text.
  • Before adding any third-party script tag to a site with a CSP already in place, check the CSP's directives first rather than assuming a silently-empty analytics dashboard means a snippet-installation mistake.
Share
Previous Article

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Next Article

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Comments

Write a comment

Related Articles

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

July 16, 2026

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

July 16, 2026

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)

July 16, 2026

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)