Loving Tina? us on GitHub0.0k
v.Latest
Documentation

Astro + Tina Setup Guide

Loading last updated info...
On This Page


TinaCMS runs side-by-side with Astro, with first-class visual editing that requires no React in your page tree. The integration ships as @tinacms/astro (a vanilla-Astro rich-text renderer) and @tinacms/bridge (a ~2 kB gzipped postMessage client that loads only inside the editor iframe).

This guide walks through local setup, content modelling, running TinaCMS, and wiring visual editing.

Getting Started

1. Initialize TinaCMS in Your Astro Site

From within your site's root directory, run:

npx @tinacms/cli@latest init

This command will prompt you with a few setup questions. When asked for the public assets directory, enter:

public

Alternatively, scaffold from the React-free starter template:

npx create-tina-app@latest --template tina-astro-starter

This sets up a blog-ready Astro Starter Template with TinaCMS and visual editing preconfigured — no React in the source tree.

Modeling Your Content

Define your content models in tina/config.ts. See the content modelling docs for the full schema reference.

Running TinaCMS

Start the dev server alongside Astro:

npx tinacms dev -c "astro dev"
Note: --port 8080 can be added after astro dev to specify a custom port.

Once running, navigate to:

http://localhost:<port>/admin/index.html
or
/admin (If using the Tina Astro Starter, which redirects to /admin/index.html)
Tip: If you encounter errors, check the Common Errors page.

You should now see the Tina admin interface, be able to select a post, save changes, and observe updates persisting to your local markdown files.

TinaCMS Admin

Enabling Visual Editing

Visual editing — click-to-focus, live preview as the editor types, side-by-side admin + page — works on Astro without React via the @tinacms/astro package. The starter has it preconfigured. For an existing site:

npm install @tinacms/astro @astrojs/node

Then in astro.config.mjs:

import node from '@astrojs/node';
export default defineConfig({
output: 'server',
adapter: node({ mode: 'standalone' }),
// ...rest of config
});
SSR is required. The bridge POSTs to a per-page refresh endpoint when content changes; that endpoint needs a server runtime. Use @astrojs/node, @astrojs/vercel, @astrojs/netlify, or any other Astro adapter — visual editing works against all of them.

The full wiring (bridge init(), form payload <script> tags, data-tina-island wrappers, tinaField() markers, the per-island endpoint) is documented in Visual Editing Setup → Astro.

Visual Editing

Project Structure

The starter and the visual-editing setup organise around four moving pieces:

  • src/lib/tina-preview.ts (the withOverlay() data-loader seam), data.ts (per-collection fetchers), islands.ts (registry of editable regions), metadata.ts (_content_source stamping for click-to-edit), queries.ts (extracts the canonical query strings from tina/__generated__/).
  • src/pages/tina-island/[name].ts — the dynamic endpoint the bridge POSTs to on every keystroke. Renders the matching component to an HTML fragment via experimental_AstroContainer.
  • src/components/islands/*.astro — pure Astro renderers (<TinaMarkdown> for rich-text, tinaField() for click-to-edit markers).
  • src/components/BaseHead.astro — emits one <script type="application/tina+json"> per form payload and loads the bridge.

See Visual Editing Setup → Astro for the full architecture.

Next Steps

For more details, visit the official TinaCMS documentation and Astro documentation. Join the TinaCMS Discord for community support.

See Also

Last Edited: May 8, 2026