Quickstart

A blog index, a rendered post, and SEO metadata. About 15 lines.

Install

The loop: list, fetch, render, describe

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

// No key needed for published, public content.
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);
}
console.log(`page ${pageInfo.page}, hasMore: ${pageInfo.hasMore}`);

// One post, rendered to HTML, with SEO ready to drop in
const post = await floggy.posts.get("hello-world", { format: "html" });
console.log(post.rendered);        // ready-to-inject HTML string
const metadata = floggy.seo.meta(post); // Next.js-compatible Metadata object

That is the whole loop: list, fetch, render, describe.

Next.js App Router

A complete post page with metadata, rendered HTML, and JSON-LD.

// app/[slug]/page.tsx
import { createClient } from "@floggy/cms";

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

export async function generateMetadata({ params }: { params: { slug: string } }) {
  const post = await floggy.posts.get(params.slug);
  return floggy.seo.meta(post); // title, description, openGraph, twitter, alternates.canonical, robots
}

export default async function PostPage({ params }: { params: { slug: string } }) {
  const post = await floggy.posts.get(params.slug, { format: "html" });
  return (
    <article>
      <h1>{post.title}</h1>
      {floggy.seo.jsonLd(post).map((node, i) => (
        <script
          key={i}
          type="application/ld+json"
          dangerouslySetInnerHTML={{ __html: JSON.stringify(node) }}
        />
      ))}
      <div dangerouslySetInnerHTML={{ __html: post.rendered ?? "" }} />
    </article>
  );
}

Drop-in feed routes

// app/sitemap.xml/route.ts
import { createClient } from "@floggy/cms";

const floggy = createClient({
  project: "projecta",
  site: { url: "blog.example.com", name: "Example", description: "My blog" },
});

export async function GET() {
  return new Response(await floggy.feeds.sitemap(), {
    headers: { "Content-Type": "application/xml" },
  });
}

The same pattern works for floggy.feeds.rss() (application/rss+xml) and floggy.feeds.robots() (text/plain).

Next steps