Overview

@floggy/cms is the single dependency you install to build a blog on Floggy. It reads your content fully typed and ready to render - html, markdown, SEO metadata, JSON-LD, and feeds - and, with an flg_ key, it writes: create a draft from Markdown, preview it, publish it. Zero runtime dependencies.

Install

Quickstart

A working blog index plus a post page, with SEO, in about 15 lines.

import { createClient } from "@floggy/cms";

const floggy = createClient({ project: "projecta" });

// Blog index
const { posts, pageInfo } = await floggy.posts.list({ page: 1, perPage: 10 });
for (const post of posts) {
  console.log(post.title, "/" + post.slug);
}

// Post page (rendered HTML + adjacent nav + SEO block + JSON-LD)
const post = await floggy.posts.get("hello-world", { format: "html" });
console.log(post.rendered);          // ready-to-inject HTML string
console.log(post.adjacent.prev);     // { slug, title } | null
const metadata = floggy.seo.meta(post); // plain Next.js-compatible Metadata object

Writing

With a key that carries posts:write (and posts:read to preview), the same client creates, previews, and publishes.

const floggy = createClient({ project: "projecta", key: process.env.FLOGGY_KEY });

// Markdown in, draft out. Nothing is live yet.
const { id } = await floggy.posts.create({
  title: "Launch Day",
  content: "## What changed\n\nWe shipped the new **editor**.",
});

// Preview by slug: unpublished posts only, so a published slug returns null.
const draft = await floggy.posts.draft("launch-day");

// Ship it.
await floggy.posts.publish(id);

Every authenticated call acts on the key owner's blog. project only selects the blog the public reads come from.

Configuration

createClient({
  project: "projecta",                 // required: the Floggy username/project
  key: process.env.FLOGGY_KEY,         // optional: flg_ key for drafts/private content
  site: {                              // optional: used by feeds.*
    url: "blog.example.com",           // public origin (protocol auto-added)
    name: "Example",                   // defaults to project name
    description: "My blog",            // defaults to "<name>'s blog"
    locale: "en",                      // defaults to "en"
  },
  fetch: customFetch,                  // optional: custom fetch implementation
});

Auth

Public reads need no key. Pass an flg_ key to read drafts and private content (posts:read), to create, update, and publish (posts:write), or to delete (posts:delete). Use a Read-only key in any frontend - a leaked read key only exposes content that is already public. Never embed an Editor or Full-access key in a frontend: it can publish and delete your posts.

const floggy = createClient({ project: "projecta", key: process.env.FLOGGY_KEY });

Methods at a glance

The client exposes five namespaces - posts, tags, seo, feeds, collections:

  • posts (public) - list, get, search
  • posts (your own, needs a key) - mine, getById, draft, create, update, publish, unpublish, delete, bulk
  • tags - list
  • seo - meta, jsonLd
  • feeds - sitemap, rss, robots
  • collections - versioned, schema-driven content stores

Standalone exports too: markdownToTiptap, tiptapToMarkdown, and slugify.

See the SDK reference for full signatures, options, and return shapes.

Errors

Every non-2xx response throws a typed error.

import { FloggyError, RateLimitError, ScopeError } from "@floggy/cms";

try {
  await floggy.posts.publish(id);
} catch (err) {
  if (err instanceof ScopeError) {
    console.log("this key needs:", err.required.join(", "));
  } else if (err instanceof RateLimitError) {
    console.log("retry after", err.retryAfter, "seconds");
  } else if (err instanceof FloggyError) {
    console.log(err.status, err.message, err.code);
  }
}

FloggyError carries status, message, code, and url. ScopeError (status 403) adds required, the scopes the endpoint asked for. RateLimitError (status 429) adds retryAfter (seconds, parsed from the Retry-After header).

Next

  • Quickstart - list, fetch, render, and add SEO in about 15 lines.
  • SDK reference - every @floggy/cms method, reads and writes, with Next.js and TanStack Start examples.
  • API reference - the REST endpoints underneath, for curl and non-SDK use.
  • Authentication - creating flg_ keys, the scope table, presets, and key-safety rules.
  • Webhooks - subscribe to post.published / post.updated and verify signatures.
  • Collections - headless, schema-driven content stores with versioning and A/B labels, driven through floggy.collections.*.