Ink CMS is our open-source headless CMS built specifically for Astro sites. It gives you a visual admin panel to manage blog posts, pages, and media — no Markdown required.

What Is Ink CMS?

Ink CMS is a lightweight, API-based content management system:

  • Open sourcegithub.com/Liteink/ink-cms
  • Self-hosted — Runs on Cloudflare Workers + D1
  • API-first — Your Astro site fetches content via REST API
  • Zero lock-in — Content is stored in SQLite, exportable anytime

It’s designed for people who want a visual editor but don’t want the complexity of WordPress or the cost of Contentful.

Live Demo

Try the admin panel at cms.liteink.co — no signup required, it’s a read-only demo.

How It Works

┌─────────────┐     REST API     ┌──────────────┐
│  Ink CMS    │ ───────────────→ │  Your Astro   │
│  (Admin UI) │   /api/posts     │  Theme        │
│             │   /api/media     │  (Static/SSR) │
└─────────────┘                  └──────────────┘
  1. You write content in the Ink CMS admin panel
  2. At build time (or runtime with SSR), your Astro theme fetches content via API
  3. Astro renders the content into static HTML

Setup Overview

Step 1 — Deploy Ink CMS

Clone the repository and deploy to Cloudflare Workers:

git clone https://github.com/Liteink/ink-cms
cd ink-cms
npm install
npm run build
npx opennextjs-cloudflare deploy

Set the ADMIN_PASSWORD environment variable to a secure value.

Step 2 — Create an API Key

In the Ink CMS admin panel, go to Settings → API Keys and create a new key. This key lets your Astro theme authenticate with the CMS.

Step 3 — Fetch Content in Astro

In your Astro page or layout, fetch posts from the CMS:

---
const res = await fetch('https://your-cms.workers.dev/api/posts', {
  headers: { 'Authorization': `Bearer ${import.meta.env.CMS_API_KEY}` },
});
const posts = await res.json();
---

Or use getStaticPaths to generate pages at build time:

---
export async function getStaticPaths() {
  const res = await fetch('https://your-cms.workers.dev/api/posts');
  const posts = await res.json();
  return posts.map(post => ({
    params: { slug: post.slug },
    props: { post },
  }));
}
---

Step 4 — Render Content

Ink CMS returns Markdown content. Use Astro’s Markdown rendering to display it:

---
import { marked } from 'marked';
const html = marked(post.content);
---
<article set:html={html} />

When to Use Ink CMS vs Markdown Files

Use Ink CMS if…Use Markdown files if…
Multiple non-technical editorsYou’re the only editor
You want a visual editorYou’re comfortable with Markdown
Content changes frequentlyContent is relatively static
You need media managementImages are minimal

Both approaches produce the same result — fast, static Astro pages.

What’s Next?