<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tony Spiro</title>
    <description>The latest articles on DEV Community by Tony Spiro (@tonyspiro).</description>
    <link>https://dev.to/tonyspiro</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F36636%2F37a4c910-90d9-40b1-9a8b-69e1ad31b4f6.jpeg</url>
      <title>DEV Community: Tony Spiro</title>
      <link>https://dev.to/tonyspiro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tonyspiro"/>
    <language>en</language>
    <item>
      <title>MCP vs Agent Skills: What's the Difference and Which Do You Need?</title>
      <dc:creator>Tony Spiro</dc:creator>
      <pubDate>Tue, 12 May 2026 22:12:48 +0000</pubDate>
      <link>https://dev.to/tonyspiro/mcp-vs-agent-skills-whats-the-difference-and-which-do-you-need-459h</link>
      <guid>https://dev.to/tonyspiro/mcp-vs-agent-skills-whats-the-difference-and-which-do-you-need-459h</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://www.cosmicjs.com/blog/mcp-vs-agent-skills" rel="noopener noreferrer"&gt;cosmicjs.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two terms keep coming up in every AI developer conversation right now: MCP (Model Context Protocol) and Agent Skills. They sound similar. They're not the same thing. Here's a clear breakdown of what each is, when to use which, and how Cosmic implements both.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is MCP?
&lt;/h2&gt;

&lt;p&gt;MCP (Model Context Protocol) is an open protocol developed by Anthropic that lets AI models connect to external tools and data sources in a standardized way. Think of it as a universal adapter that allows an AI assistant like Claude to read files, query databases, call APIs, and interact with services, all through a consistent interface.&lt;/p&gt;

&lt;p&gt;MCP runs as a server that your AI client connects to. Once connected, the AI can discover and use whatever tools the MCP server exposes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cosmic MCP Server:&lt;/em&gt; Cosmic ships a native MCP server that gives AI assistants direct access to your content. Claude, Cursor, and other MCP-compatible clients can read objects, query content types, fetch media, and understand your content model, all without you writing any integration code.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Agent Skills?
&lt;/h2&gt;

&lt;p&gt;Agent Skills are pre-built, reusable capabilities you can attach to AI coding assistants like Cursor, Claude Code, and GitHub Copilot. Where MCP gives an AI access to data, Agent Skills give an AI knowledge of how to do specific tasks in a specific codebase or platform.&lt;/p&gt;

&lt;p&gt;CosmicAgent Skills teach your coding assistant how to work with Cosmic specifically: how to structure queries, how to use the TypeScript SDK, how to model content, and how to build features against the Cosmic REST API.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Key Difference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;MCP&lt;/em&gt; = data access. The AI can read and write to your Cosmic bucket in real time.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Agent Skills&lt;/em&gt; = task knowledge. The AI knows how to build with Cosmic correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are complementary, not competing.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use MCP
&lt;/h2&gt;

&lt;p&gt;Use the Cosmic MCP Server when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want Claude or another AI assistant to query your live content&lt;/li&gt;
&lt;li&gt;You're using an AI chat interface and want it to have context about your bucket&lt;/li&gt;
&lt;li&gt;You want AI to help you manage, audit, or restructure your content
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Add Cosmic MCP to your Claude config&lt;/span&gt;
npx @cosmicjs/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When to Use Agent Skills
&lt;/h2&gt;

&lt;p&gt;Use Cosmic Agent Skills when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're building features in Cursor, Claude Code, or Copilot&lt;/li&gt;
&lt;li&gt;You want your coding assistant to generate correct Cosmic SDK code automatically&lt;/li&gt;
&lt;li&gt;You want to avoid copy-pasting docs into every prompt&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using Both Together
&lt;/h2&gt;

&lt;p&gt;The most powerful setup uses both. Your coding assistant has Agent Skills so it generates correct Cosmic code, and it has MCP access so it can query your actual live bucket while building. It can look up your real content types, check what fields exist, and generate code that matches your exact schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Agent Skills ensure your assistant generates correct SDK usage&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createBucketClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@cosmicjs/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createBucketClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;bucketSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_BUCKET_SLUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;readKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_READ_KEY&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// MCP gives the assistant live access to your actual content types&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;objects&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-actual-type-slug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// AI knows this from MCP&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title,slug,metadata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;If you're building with AI assistants, you want both. MCP for live data access. Agent Skills for correct code generation. Cosmic ships both natively.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cosmicjs.com" rel="noopener noreferrer"&gt;Start free with Cosmic&lt;/a&gt; and set up both in under 10 minutes.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>webdev</category>
      <category>cms</category>
    </item>
    <item>
      <title>Astro vs Next.js: Which Framework Should You Use in 2026?</title>
      <dc:creator>Tony Spiro</dc:creator>
      <pubDate>Tue, 12 May 2026 22:12:26 +0000</pubDate>
      <link>https://dev.to/tonyspiro/astro-vs-nextjs-which-framework-should-you-use-in-2026-5e2h</link>
      <guid>https://dev.to/tonyspiro/astro-vs-nextjs-which-framework-should-you-use-in-2026-5e2h</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://www.cosmicjs.com/blog/astro-vs-nextjs-2026" rel="noopener noreferrer"&gt;cosmicjs.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choosing between Astro and Next.js in 2026? Both are excellent frameworks, but they solve different problems. This guide breaks down the real tradeoffs so you can make the right call for your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Short Answer
&lt;/h2&gt;

&lt;p&gt;Use Astro when your site is content-heavy and you want maximum performance with minimal JavaScript. Use Next.js when you need a full-stack React application with dynamic data, auth, and API routes.&lt;/p&gt;

&lt;p&gt;Both work seamlessly with Cosmic as your headless CMS.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Astro Does Well
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Zero JS by default, ships only what you need&lt;/li&gt;
&lt;li&gt;Island architecture for selective hydration&lt;/li&gt;
&lt;li&gt;Supports React, Vue, Svelte, and more in the same project&lt;/li&gt;
&lt;li&gt;Best-in-class for static content sites, blogs, and marketing pages&lt;/li&gt;
&lt;li&gt;Built-in content collections&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Next.js Does Well
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Full-stack React with App Router and Server Components&lt;/li&gt;
&lt;li&gt;API routes and server actions built in&lt;/li&gt;
&lt;li&gt;ISR and on-demand revalidation&lt;/li&gt;
&lt;li&gt;Largest ecosystem and community&lt;/li&gt;
&lt;li&gt;Best for dynamic applications, dashboards, and e-commerce&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance Comparison
&lt;/h2&gt;

&lt;p&gt;Astro wins on raw page weight for content sites. No framework JavaScript ships by default. Next.js with proper server components is competitive, but requires more discipline to keep bundles lean.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use Astro
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Marketing sites and landing pages&lt;/li&gt;
&lt;li&gt;Blogs and documentation&lt;/li&gt;
&lt;li&gt;Content-heavy sites where SEO is the primary goal&lt;/li&gt;
&lt;li&gt;Teams that want to mix component frameworks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Use Next.js
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;SaaS applications&lt;/li&gt;
&lt;li&gt;E-commerce with dynamic inventory&lt;/li&gt;
&lt;li&gt;Apps with complex auth flows&lt;/li&gt;
&lt;li&gt;Teams already invested in the React ecosystem&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using Both with Cosmic
&lt;/h2&gt;

&lt;p&gt;Cosmic's REST API and TypeScript SDK work identically in both frameworks. Here's how to fetch content in each:&lt;/p&gt;

&lt;h3&gt;
  
  
  Astro
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createBucketClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@cosmicjs/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createBucketClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;bucketSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_BUCKET_SLUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;readKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_READ_KEY&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;objects&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog-posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title,slug,metadata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Next.js App Router
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createBucketClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@cosmicjs/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createBucketClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;bucketSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_BUCKET_SLUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;readKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_READ_KEY&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BlogPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;objects&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog-posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title,slug,metadata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;}&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same SDK, same API, same content model. Switch frameworks without touching your content.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Verdict
&lt;/h2&gt;

&lt;p&gt;Astro and Next.js are not competitors in the traditional sense. They serve different primary use cases. The better question is: what are you building?&lt;/p&gt;

&lt;p&gt;Content site with SEO focus? Astro. Full-stack application? Next.js. Both? Cosmic works with either.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cosmicjs.com" rel="noopener noreferrer"&gt;Start free with Cosmic&lt;/a&gt; and build with whichever framework fits your project.&lt;/p&gt;

</description>
      <category>astro</category>
      <category>nextjs</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>AI as Coordinator: Why SaaS Must Bundle or Die</title>
      <dc:creator>Tony Spiro</dc:creator>
      <pubDate>Tue, 12 May 2026 16:03:23 +0000</pubDate>
      <link>https://dev.to/tonyspiro/ai-as-coordinator-why-saas-must-bundle-or-die-5c9b</link>
      <guid>https://dev.to/tonyspiro/ai-as-coordinator-why-saas-must-bundle-or-die-5c9b</guid>
      <description>&lt;p&gt;For most of the last decade, the conventional wisdom in software was simple: use the best tool for every job. The CRM that wins on contact management. The CMS that wins on editor experience. The analytics platform that wins on dashboards. The best-of-breed stack, stitched together by integrations and held together by the humans navigating between them.&lt;/p&gt;

&lt;p&gt;That era is over. I don't think this is coming. I think it has already happened. And I don't think most SaaS companies understand the implications yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Unbundling Era Made Sense When Humans Were the Coordinators
&lt;/h2&gt;

&lt;p&gt;The logic behind best-of-breed stacks was always human logic. A skilled operator could hold context across a dozen tools. A marketing manager could pull data from one platform, paste it into another, run a report from a third, and synthesize the whole picture in her head. The friction of context-switching was manageable because humans are actually pretty good at it. We pattern-match across interfaces. We tolerate inconsistency. We remember which export format a specific tool uses.&lt;/p&gt;

&lt;p&gt;The integration layer was built for us. Zapier, Make, and dozens of custom webhooks exist because humans needed to connect tools they were already using. The business value was locked inside each individual product. The human was the orchestration layer.&lt;/p&gt;

&lt;p&gt;So the market optimized for exactly that model. Single-purpose tools got sharper, deeper, and more opinionated. The pitch was always the same: we do one thing and we do it better than anyone. If you want the best email tool, use us. If you want the best CMS, use us. Mix and match as needed.&lt;/p&gt;

&lt;p&gt;It was a good model. For a while.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agents Don't Care About Dashboard Design
&lt;/h2&gt;

&lt;p&gt;Here's what changes when AI agents become the coordinators of business operations: agents don't navigate between tools the way humans do. They don't have the cognitive flexibility to tolerate seams. They operate through APIs, CLIs, and MCPs, and every API boundary is a potential failure point: an authentication handoff that breaks, a data schema that doesn't translate cleanly, a rate limit that introduces latency, an error state that the agent doesn't know how to recover from.&lt;/p&gt;

&lt;p&gt;Agents don't care about dashboard design. They don't appreciate a beautiful UI. The entire value proposition of the best-of-breed stack collapses when the end user is not a human.&lt;/p&gt;

&lt;p&gt;An agent operating across 12 separate SaaS tools is not more capable than an agent operating in one unified system. It's more fragile. More likely to fail at a handoff. More likely to produce inconsistent output. More expensive to maintain. More difficult to debug.&lt;/p&gt;

&lt;p&gt;The seams that humans could paper over with judgment and context-switching become hard failures when an agent hits them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The New Moat Isn't UI. It's Vertical Integration.
&lt;/h2&gt;

&lt;p&gt;This is where I think much of the software industry is getting it wrong. A lot of SaaS companies are responding to the AI moment by adding AI features. A copilot here. An AI-assisted editor there. An auto-summarize button on the dashboard. These features are fine, but they don't change the fundamental problem.&lt;/p&gt;

&lt;p&gt;The companies that will win the next decade are not the ones that added AI on top of their existing product. They're the ones that rethought the product architecture entirely, with agents as the primary user.&lt;/p&gt;

&lt;p&gt;The new moat is vertical integration. It's owning the full stack that an agent needs to do a job, in a single system, with a single data model, through a single API.&lt;/p&gt;

&lt;p&gt;The single-product SaaS company with a great UI is not just at a disadvantage. It is structurally exposed.&lt;/p&gt;

&lt;h2&gt;
  
  
  From User Experience to Agent Experience
&lt;/h2&gt;

&lt;p&gt;For the last decade, premium software competed on UX. Smoother onboarding. Cleaner dashboards. More intuitive editors. The best product was the one your team actually wanted to open in the morning.&lt;/p&gt;

&lt;p&gt;That era produced real value. But it also produced an entire generation of software optimized for the wrong user.&lt;/p&gt;

&lt;p&gt;The new benchmark is Agent Experience. AX. How well does your platform perform when the user is an AI agent making thousands of API calls, not a human clicking through a dashboard?&lt;/p&gt;

&lt;p&gt;AX is not about aesthetics. It is about architecture. A high-AX platform has a unified data model, a clean and comprehensive API, minimal failure surfaces at integration boundaries, and built-in orchestration so agents don't need to reach outside the system to complete a workflow.&lt;/p&gt;

&lt;p&gt;A vertically integrated platform is not just more convenient for agents. It is architecturally superior for them. Every seam an agent doesn't have to cross is a failure point eliminated, a latency reduced, a context preserved.&lt;/p&gt;

&lt;p&gt;The logical endpoint of this architecture is a platform where agents don't just create content, they also measure its performance and act on what they learn. When the same system owns the content object and the pageview that came from it, the loop closes. Write, ship, measure, learn, all inside one platform, all accessible to your agents without a single third-party integration. That is what vertically integrated AX looks like in practice. We are building toward it.&lt;/p&gt;

&lt;p&gt;UX won the last decade. AX wins the next one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Loses
&lt;/h2&gt;

&lt;p&gt;The companies most at risk are the ones whose entire value proposition was "we do one thing better than anyone."&lt;/p&gt;

&lt;p&gt;Point solutions that relied on being the best-in-class editor, the best-in-class analytics view, or the best-in-class content modeling interface are going to find that the interface advantage no longer matters when agents are the users. An agent doesn't prefer your drag-and-drop UI. It calls your API.&lt;/p&gt;

&lt;p&gt;The companies that built moats through beautiful interfaces are going to find that those moats are much shallower than they thought.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Wins
&lt;/h2&gt;

&lt;p&gt;The companies that win will have a few characteristics in common.&lt;/p&gt;

&lt;p&gt;First, they'll have a unified data model. Second, they'll expose a clean, comprehensive API as the primary interface. Third, they'll own the vertical. Fourth, they'll have built-in orchestration.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Headless CMS Example
&lt;/h2&gt;

&lt;p&gt;The headless CMS space is a useful lens here, because it's a sector that went through aggressive unbundling in the last five years and is now running directly into this problem.&lt;/p&gt;

&lt;p&gt;The headless CMS companies that survive this shift will be the ones that extended beyond pure content APIs before the window closed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cosmic as the Model
&lt;/h2&gt;

&lt;p&gt;I'm not writing this as an abstract observation. This is the exact bet we made at Cosmic.&lt;/p&gt;

&lt;p&gt;Today, Cosmic is a single system that covers content management, media processing and delivery, AI agent infrastructure, workflow automation, and deployment. Our customers' agents can write a content draft, pull from the media library, run it through a publishing workflow, and deploy it, all through one API, in one system, with one data model.&lt;/p&gt;

&lt;p&gt;When FINN, one of our customers, describes the value, Co-Founder Maximilian Wuhr puts it simply: "Cosmic is: us never having to ask a developer to change anything on the backend of our website."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Window Is Shorter Than You Think
&lt;/h2&gt;

&lt;p&gt;The companies that figure this out in the next 18 months will build the infrastructure their AI-native customers depend on. The companies that wait are betting that their existing moats hold longer than the market is moving.&lt;/p&gt;

&lt;p&gt;Bundling isn't a retreat from the sophistication of the unbundled era. It's the appropriate response to the fact that the coordinator changed.&lt;/p&gt;

&lt;p&gt;Bundle or die isn't hyperbole. It's the engineering reality of building for agents.&lt;/p&gt;

&lt;p&gt;UX won the last decade. AX wins the next one.&lt;/p&gt;




&lt;p&gt;If you're building for the agentic era and want to see what integrated depth actually looks like in production, &lt;a href="https://www.cosmicjs.com" rel="noopener noreferrer"&gt;start free at cosmicjs.com&lt;/a&gt; or &lt;a href="https://calendly.com/tonyspiro/general-meeting" rel="noopener noreferrer"&gt;book a 30-minute intro with Tony&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tony Spiro is the CEO of Cosmic. He writes about building AI-native teams, headless CMS architecture, and the future of content infrastructure.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>saas</category>
      <category>webdev</category>
      <category>architecture</category>
    </item>
    <item>
      <title>What Agent-Native Means for Your Content Infrastructure</title>
      <dc:creator>Tony Spiro</dc:creator>
      <pubDate>Mon, 11 May 2026 21:41:02 +0000</pubDate>
      <link>https://dev.to/tonyspiro/what-agent-native-means-for-your-content-infrastructure-51oi</link>
      <guid>https://dev.to/tonyspiro/what-agent-native-means-for-your-content-infrastructure-51oi</guid>
      <description>&lt;p&gt;"Agent-native" is being claimed by a lot of companies right now. Here's what it actually means at the content infrastructure layer — where agents read, write, and publish the content that everything else depends on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Every Layer Is Being Redesigned
&lt;/h2&gt;

&lt;p&gt;Every layer of the software stack is being redesigned for AI agents. The frontend layer, the code layer, the deployment layer. But there's one layer getting less attention — and it's the one agents depend on most: the content infrastructure layer. That's the CMS.&lt;/p&gt;

&lt;p&gt;Here's what I think "agent-native" actually means at that layer, and why it matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agents Need to Read, Write, and Publish Content
&lt;/h2&gt;

&lt;p&gt;Let's start with the obvious: AI agents work with content. They generate it, organize it, update it, and publish it. The CMS is where that content lives. So if your CMS wasn't built for agents to interact with directly, your entire AI workflow has a bottleneck at the most important layer.&lt;/p&gt;

&lt;p&gt;A traditional CMS was designed for a human editor sitting at a dashboard. An agent-native CMS is designed for agents — and humans — to operate it equally well.&lt;/p&gt;

&lt;p&gt;For Cosmic, this meant four concrete things:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First:&lt;/strong&gt; The API had to be simple enough for any AI agent to consume without special training. REST over HTTP, predictable URL patterns, JSON responses. Not a custom query language. Not a schema you need to introspect before you can use it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second:&lt;/strong&gt; Agents needed to be first-class objects in the product. Not bolt-on integrations. Not webhooks you configure manually. Native AI agents — Team, Content, Code, Computer Use — that live in your workspace and operate on your content autonomously.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third:&lt;/strong&gt; The CMS had to connect to where developers already work. That's your IDE. So we built an MCP Server and Agent Skills for Cursor, Claude Code, and GitHub Copilot. Your AI coding tool can now read and write CMS content without leaving your editor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fourth:&lt;/strong&gt; Agents needed to chain together. A Content Agent drafts an article. A Code Agent updates the front-end component. A Computer Use Agent cross-posts to social. A Team Agent notifies the editor in Slack. This is a workflow — and it needs to run on a schedule or a webhook trigger, without a human in the loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Unlocks for Teams in 2026
&lt;/h2&gt;

&lt;p&gt;When your content infrastructure is genuinely agent-native, a few things become possible that weren't before.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content velocity stops being a headcount problem.&lt;/strong&gt; A single editor working with a team of content agents can produce, manage, and publish at a scale that previously required a full content department.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developers get their time back.&lt;/strong&gt; When agents handle the routine CMS work — bulk updates, content audits, migration tasks — developers can focus on the work that actually requires human judgment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The feedback loop between content and code collapses.&lt;/strong&gt; When your Content Agent and your Code Agent are in the same workflow, a content change can trigger a code update, a preview deployment, and a Slack notification in a single automated run.&lt;/p&gt;

&lt;p&gt;This is not a future state. These are things teams are doing with Cosmic today.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CMS Is the Critical Layer
&lt;/h2&gt;

&lt;p&gt;Every AI agent that touches your product — regardless of what framework it's built in or which LLM it runs on — eventually needs to read or write content. That makes the CMS the most critical layer in an agent-native stack.&lt;/p&gt;

&lt;p&gt;And it's the layer that will determine whether your agent workflows are fast, reliable, and actually useful, or slow, fragile, and constantly requiring human intervention.&lt;/p&gt;

&lt;p&gt;Agent-native content infrastructure is not about adding an AI button to a dashboard. It's about rebuilding the CMS from the ground up for a world where agents and humans work on the same content, in the same system, at the same time.&lt;/p&gt;

&lt;p&gt;That's what we're building at Cosmic.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cosmicjs.com/ai" rel="noopener noreferrer"&gt;See how Cosmic's AI Agents work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://app.cosmicjs.com/signup" rel="noopener noreferrer"&gt;Start building for free — no credit card required&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://calendly.com/tonyspiro/cosmic-intro" rel="noopener noreferrer"&gt;Book time with Tony&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;I'm the CEO of Cosmic, an AI-powered headless CMS. I write about building AI-native teams and the future of content infrastructure.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on the Cosmic blog: &lt;a href="https://www.cosmicjs.com/blog/agent-native-content-infrastructure" rel="noopener noreferrer"&gt;https://www.cosmicjs.com/blog/agent-native-content-infrastructure&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>cms</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why Cosmic Uses REST (and Why That's the Right Call in 2026)</title>
      <dc:creator>Tony Spiro</dc:creator>
      <pubDate>Mon, 11 May 2026 21:37:22 +0000</pubDate>
      <link>https://dev.to/tonyspiro/why-cosmic-uses-rest-and-why-thats-the-right-call-in-2026-5170</link>
      <guid>https://dev.to/tonyspiro/why-cosmic-uses-rest-and-why-thats-the-right-call-in-2026-5170</guid>
      <description>&lt;h1&gt;
  
  
  Why Cosmic Uses REST (and Why That's the Right Call in 2026)
&lt;/h1&gt;

&lt;p&gt;Every few years, a new API paradigm gets declared the future. GraphQL had its moment. And it's genuinely good — for certain use cases. But "good for certain use cases" and "better default for most teams" are different claims. REST is still the right default, and in 2026 there's a new reason it matters: AI agents.&lt;/p&gt;

&lt;p&gt;Here's an honest breakdown of the tradeoffs, and why Cosmic is REST-first by design.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Honest GraphQL vs REST Comparison
&lt;/h2&gt;

&lt;p&gt;Let's be direct about where each one wins.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where GraphQL excels
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Precisely shaped responses.&lt;/strong&gt; GraphQL lets clients request exactly the fields they need. On mobile or low-bandwidth environments, this can meaningfully reduce payload size.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single endpoint for complex graphs.&lt;/strong&gt; When your data has deeply nested relationships and you need to traverse them in a single request, GraphQL's query model can simplify client code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rapid iteration on the client side.&lt;/strong&gt; Frontend teams can adjust what data they fetch without waiting for a backend API change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type-safe schema introspection.&lt;/strong&gt; Tooling like Apollo DevTools and GraphQL Codegen is genuinely excellent for teams that invest in the ecosystem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Where REST wins
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity.&lt;/strong&gt; A REST endpoint is a URL. Any HTTP client — curl, fetch, Postman, a Python script, an AI agent — can consume it without understanding a schema or learning a query language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cacheability.&lt;/strong&gt; HTTP caching is built for REST. GET requests to a stable URL can be cached at the CDN layer with no additional tooling. GraphQL's POST-by-default convention makes this harder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debuggability.&lt;/strong&gt; When something breaks, a REST API gives you a URL you can open in a browser, paste into Postman, or log directly. GraphQL errors can be harder to trace without dedicated tooling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ecosystem breadth.&lt;/strong&gt; REST is universal. Every language, every framework, every tool speaks REST.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational simplicity.&lt;/strong&gt; No query parser, no resolver overhead, no N+1 query problems to solve. For most content APIs, the queries are simple enough that REST's structure is a feature, not a limitation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The honest verdict on GraphQL
&lt;/h3&gt;

&lt;p&gt;GraphQL makes sense for complex, client-driven data fetching scenarios — large product catalogs with dozens of relationship types, mobile apps with strict bandwidth constraints, teams with mature frontend infrastructure. It's a real tool for real problems.&lt;/p&gt;

&lt;p&gt;But most content APIs are not that complex. A blog post has a title, a body, some metadata, and maybe a category. A landing page has sections and a hero image. REST handles these cases cleanly, with less overhead and more cacheability.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why 2026 Changes the Calculation: AI Agents
&lt;/h2&gt;

&lt;p&gt;Here's the new variable: AI agents are now part of most content workflows. And REST is dramatically better suited for agent consumption than GraphQL.&lt;/p&gt;

&lt;h3&gt;
  
  
  REST endpoints are trivially parseable by LLMs
&lt;/h3&gt;

&lt;p&gt;A REST endpoint is a URL with predictable structure: &lt;code&gt;GET /objects?type=blog-posts&amp;amp;limit=10&lt;/code&gt;. An AI agent can construct this URL from a natural language instruction without understanding a schema. The response is JSON — structured, flat, predictable.&lt;/p&gt;

&lt;p&gt;GraphQL requires the agent to understand the schema, construct a valid query document, and handle the query syntax correctly. That's more tokens, more failure modes, and more prompting complexity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caching matters for agent workflows
&lt;/h3&gt;

&lt;p&gt;AI agents often make repeated, similar requests — checking content status, fetching object counts, reading metadata. CDN-cached REST responses make this cheap and fast. GraphQL's POST-by-default pattern bypasses CDN caching entirely, meaning every agent request hits your origin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Direct URL-based queries are auditable
&lt;/h3&gt;

&lt;p&gt;When an AI agent fetches content via a REST endpoint, the request is a plain URL you can log, inspect, and replay. This matters for debugging agent workflows and for understanding what your agents are actually doing.&lt;/p&gt;

&lt;h3&gt;
  
  
  The emerging standard: REST + structured JSON
&lt;/h3&gt;

&lt;p&gt;Tools like Model Context Protocol (MCP) and the major LLM provider SDKs are all built around REST + JSON. The ecosystem is converging on REST as the lingua franca for agent-to-service communication — because it's the most universally parseable format.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cosmic's REST API in Practice
&lt;/h2&gt;

&lt;p&gt;Cosmic's REST API is designed to be fast, predictable, and easy for both humans and AI agents to consume.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sub-100ms response times&lt;/strong&gt; globally via CDN caching. Whether it's a developer building a Next.js page or an AI agent fetching content to include in a generated article, the API is consistently fast.&lt;/p&gt;

&lt;p&gt;Here's a simple example using the Cosmic TypeScript SDK — which wraps the REST API with full type safety:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createBucketClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@cosmicjs/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createBucketClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;bucketSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_BUCKET_SLUG&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;readKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_READ_KEY&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog-posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metadata.teaser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;created_at&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-created_at&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SDK compiles down to simple REST requests. No schema introspection. No query document compilation. Just a URL, a JSON response, and TypeScript types.&lt;/p&gt;

&lt;p&gt;You can also call the REST API directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://api.cosmicjs.com/v3/buckets/my-bucket/objects?type=blog-posts&amp;amp;limit=10&amp;amp;read_key=YOUR_READ_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That URL is cacheable at the CDN layer, inspectable in a browser, and consumable by any HTTP client — including an AI agent with no Cosmic-specific knowledge whatsoever.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Decision in Plain Terms
&lt;/h2&gt;

&lt;p&gt;For most content APIs, REST is faster to implement, easier to cache, simpler to debug, and better suited for the AI-agent workflows that are becoming standard in 2026.&lt;/p&gt;

&lt;p&gt;GraphQL is the right call when you have complex, client-driven data fetching needs and a team ready to invest in the ecosystem. Those situations exist. But they're not the default.&lt;/p&gt;

&lt;p&gt;Cosmic is REST-first because REST is the right default for content delivery — and because in a world where AI agents are increasingly reading and writing your content, the simplicity and cacheability of REST becomes even more valuable, not less.&lt;/p&gt;




&lt;h2&gt;
  
  
  Start Building with Cosmic
&lt;/h2&gt;

&lt;p&gt;The Cosmic REST API is available on the free plan, no credit card required. Fetch your first objects in under five minutes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.cosmicjs.com/signup" rel="noopener noreferrer"&gt;&lt;strong&gt;Get started free →&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Want to talk through your architecture? &lt;a href="https://calendly.com/tonyspiro/cosmic-intro" rel="noopener noreferrer"&gt;Book time with Tony, Cosmic's CEO.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://www.cosmicjs.com/blog/why-rest-api-headless-cms-2026" rel="noopener noreferrer"&gt;Cosmic blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>api</category>
      <category>typescript</category>
      <category>ai</category>
    </item>
    <item>
      <title>How to Build an AI-Native Team: A Practical Framework for Working Alongside Agents</title>
      <dc:creator>Tony Spiro</dc:creator>
      <pubDate>Fri, 08 May 2026 16:04:41 +0000</pubDate>
      <link>https://dev.to/tonyspiro/how-to-build-an-ai-native-team-a-practical-framework-for-working-alongside-agents-452m</link>
      <guid>https://dev.to/tonyspiro/how-to-build-an-ai-native-team-a-practical-framework-for-working-alongside-agents-452m</guid>
      <description>&lt;p&gt;Cloudflare just published a striking signal. In a letter to their team announcing a workforce reduction of more than 1,100 people, co-founders Matthew Prince and Michelle Zatlyn wrote: "Cloudflare's usage of AI has increased by more than 600% in the last three months alone. Employees across the company, from engineering to HR to finance to marketing, run thousands of AI agent sessions each day to get their work done." They weren't talking about AI tools. They were talking about AI agents. Running autonomously. Integrated into real work. At scale.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.cloudflare.com/building-for-the-future/" rel="noopener noreferrer"&gt;Cloudflare's letter&lt;/a&gt; makes clear what a lot of business leaders are quietly realizing: the companies that figured out how to work alongside agents aren't just more efficient. They're operating in a fundamentally different mode. The question isn't whether agents are coming to your industry. It's whether your team knows how to work with them when they arrive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Most AI Rollouts Fail
&lt;/h2&gt;

&lt;p&gt;Here's what I see happen at most companies: someone on the leadership team decides it's time to "embrace AI." They buy a handful of tools, maybe subscribe to a few AI writing platforms or coding assistants, send a Slack message encouraging the team to use them, and wait for transformation to happen.&lt;/p&gt;

&lt;p&gt;It doesn't happen.&lt;/p&gt;

&lt;p&gt;The tools get used occasionally, like a tab you open and forget about. Productivity ticks up slightly, and the team calls it a success. But nothing structurally changes about how work gets done.&lt;/p&gt;

&lt;p&gt;The problem isn't the tools. It's that giving your team AI tools is completely different from empowering them to work alongside AI agents. One is autocomplete at scale. The other is a new organizational model.&lt;/p&gt;

&lt;p&gt;Most companies are stuck at the tool stage. They're using AI to speed up individual tasks. The teams pulling ahead are building systems where humans and agents execute together, with clear roles, clear handoffs, and clear checkpoints.&lt;/p&gt;

&lt;p&gt;This post is a framework for getting there. Everything in it is drawn from how we actually operate at Cosmic. Take what fits your team and apply it directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Framework: How Humans and Agents Execute Together
&lt;/h2&gt;

&lt;p&gt;Before getting into specifics, here's the mental model that shapes everything else:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agents generate. Humans decide.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every workflow I've built that works is structured around this principle. Agents handle the volume, the consistency, the first pass, the research, the drafting, the monitoring. Humans handle the judgment calls, the approvals, the external communications, the strategy.&lt;/p&gt;

&lt;p&gt;When you try to flip this, or when you skip the human step entirely to move faster, you get burned. I'll share some of the mistakes I made below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Identify Which Work Is Ready to Hand to an Agent
&lt;/h2&gt;

&lt;p&gt;Not everything should go to an agent. The failure mode I see most often is trying to automate work that requires judgment before you've articulated what good judgment looks like.&lt;/p&gt;

&lt;p&gt;A useful filter: is this work repeatable, documentable, and reviewable?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repeatable&lt;/strong&gt; means it happens on a consistent cadence or follows a consistent pattern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentable&lt;/strong&gt; means you can write down what good output looks like in enough detail that an agent can match it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reviewable&lt;/strong&gt; means a human can evaluate the output in a reasonable window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Work involving novel situations, relationship judgment, strategic bets, or creative leaps is not ready for agents yet. Keep humans there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to apply this to your team:&lt;/strong&gt; List the recurring work your team does each week. For each item, ask: could I write instructions clear enough that a smart contractor on day one could produce a good first draft? If yes, that work is ready for an agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Define Roles, Not Just Tasks
&lt;/h2&gt;

&lt;p&gt;The shift from "AI tools" to "AI-native team" happens when you stop thinking about what AI can help you do and start thinking about what role an agent can own.&lt;/p&gt;

&lt;p&gt;At Cosmic, we have agents with defined roles, scopes, and responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mia (Content Agent):&lt;/strong&gt; Owns the content pipeline. Researches topics, drafts posts, saves them to our CMS as drafts, generates featured images, and pings the team for review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Marcus (Engineering Agent):&lt;/strong&gt; Works in our codebase. Can read and write code, create branches, and open pull requests. Scoped to specific repositories, can't deploy to production without an engineer reviewing and merging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lisa (Growth Agent):&lt;/strong&gt; Runs a Monday morning competitor analysis without being asked. Checks what others published or changed, flags keyword gaps, and posts findings to Slack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sarah (Outbound):&lt;/strong&gt; Identifies potential customers and drafts outreach. Connected to our Gmail accounts, composes tailored messages, and sends emails on our behalf after human review.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Giving each agent a real name changed how our team relates to them. Instead of saying "I'll run that through the content tool," someone says "Mia is drafting it." That small shift reinforces the collaborator mindset and makes ownership clearer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to apply this to your team:&lt;/strong&gt; Pick one role that's currently overloaded or understaffed. Write a one-page job description for an AI agent that could own a portion of that work: their responsibilities, their access, their quality bar, and the human checkpoint at the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Give Agents the Right Context and Access
&lt;/h2&gt;

&lt;p&gt;An agent is only as good as the context it has and the systems it can reach.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A clear role definition.&lt;/strong&gt; What is this agent responsible for? What is it explicitly not responsible for?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access to the right systems.&lt;/strong&gt; Our content agents can read and write objects in Cosmic directly. Without that access, every output has to be manually entered somewhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The right information at runtime.&lt;/strong&gt; An agent running a competitor analysis needs to be able to browse competitor websites, not just work from memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A feedback loop.&lt;/strong&gt; When a human reviews and revises an agent's output, that correction shapes future runs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Security and access control matter here. Agents should have the minimum access required for their role. Our content agents can write drafts but not publish. Our code agents can open pull requests but not merge to main.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to apply this to your team:&lt;/strong&gt; For each agent you're setting up, answer these four questions: (1) What data does it need? (2) What systems does it need access to? (3) What can it never do without human approval? (4) What does success look like?&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Design the Human-Agent Handoff
&lt;/h2&gt;

&lt;p&gt;The handoff is where most human-AI workflows succeed or fail. Here's the model we've landed on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agents draft, humans approve and publish&lt;/li&gt;
&lt;li&gt;Agents queue messages, humans review and send&lt;/li&gt;
&lt;li&gt;Agents open pull requests, engineers review and merge&lt;/li&gt;
&lt;li&gt;Agents surface recommendations, leadership decides&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A well-configured agent should hand you a draft that's 70 to 80 percent ready. Your job is the final 20 percent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A mistake I made early:&lt;/strong&gt; we shipped an outbound email workflow without proper guardrails. The agent had no instruction to check whether a contact had already been emailed, so several people received the same outreach two or three times. The fix wasn't a smarter model. It was a better review process and tighter instructions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to apply this to your team:&lt;/strong&gt; For each agent workflow, explicitly define the handoff: who reviews, what they're checking for, how they approve or reject, and what happens next. Write it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Design Workflows Where Humans and Agents Execute in Parallel
&lt;/h2&gt;

&lt;p&gt;The highest-leverage version of this model isn't sequential. It's parallel: humans and agents working on different parts of the same problem simultaneously.&lt;/p&gt;

&lt;p&gt;Here's a concrete example from our content workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Lisa monitors competitors and flags keyword gaps every Monday (agent)&lt;/li&gt;
&lt;li&gt;I prioritize which topics to pursue that week (human)&lt;/li&gt;
&lt;li&gt;Mia drafts posts for the approved topics, generates images, saves to CMS (agent)&lt;/li&gt;
&lt;li&gt;I review, revise the final 20 percent, approve (human)&lt;/li&gt;
&lt;li&gt;Mia handles scheduling, social copy, and cross-linking (agent)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result is a content operation run by one human that would take a team of four or five people to run manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mindset Shift That Makes This Work
&lt;/h2&gt;

&lt;p&gt;Stop thinking of agents as tools and start thinking of them as collaborators with real roles.&lt;/p&gt;

&lt;p&gt;A tool mindset says "let me use AI to write this post faster." A collaborator mindset says "Mia owns the first draft of every post; my job is the editorial pass."&lt;/p&gt;

&lt;p&gt;Most people use about 10 percent of what agents are capable of. They give agents safe, small tasks and leave most of the capability on the table. &lt;strong&gt;Stress-test your agents.&lt;/strong&gt; Give them harder problems, more context than feels comfortable, more responsibility than you think they can handle. The ceiling is consistently higher than people expect.&lt;/p&gt;

&lt;p&gt;The other shift: stop treating agents as executors and start treating them as collaborators in the thinking. When you're about to give an agent a task, try asking what it thinks you should do instead. Ask for three options. Ask what you might be missing. The best outputs I've gotten from agents came not from directives but from dialogue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Start: A Bottleneck-First Framework
&lt;/h2&gt;

&lt;p&gt;Don't start with a technology roadmap. Start with your biggest bottlenecks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Identify your biggest bottlenecks first.&lt;/strong&gt; Where is your team slowest? Where does work pile up, stall, or get dropped? That's where agents have the highest ROI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Map the inputs and outputs.&lt;/strong&gt; Before you touch any tooling, define the task precisely: what does it need to start, and what does done look like? If you can clearly answer both, an agent can own the work between them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Build backwards from the bottleneck.&lt;/strong&gt; Design the workflow from the desired outcome back to the first action. Ask: what agent handles this, what tools does it need, where are the handoff points, and where do humans need to check the work?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Run one workflow for 30 days before adding another.&lt;/strong&gt; Depth before breadth. Get one workflow actually working and reliable before you build the next one. After 30 days with Mia, our content output had improved enough that we had real capacity to invest in the next workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Compounding Advantage
&lt;/h2&gt;

&lt;p&gt;Teams building this capability now are accumulating organizational infrastructure that compounds. Every tighter instruction set, every faster review loop, every workflow that shifts from sequential to parallel: these aren't one-time gains. They're the foundation for absorbing whatever capability improvements come next.&lt;/p&gt;

&lt;p&gt;You don't have to build everything at once. Start with one workflow, one agent, one handoff. Get that right. Then build on it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tony Spiro is the CEO of &lt;a href="https://www.cosmicjs.com" rel="noopener noreferrer"&gt;Cosmic&lt;/a&gt;, an AI-powered headless CMS. He writes about building AI-native teams, headless CMS architecture, and the future of content infrastructure.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://www.cosmicjs.com/blog/how-to-build-an-ai-native-team-practical-framework" rel="noopener noreferrer"&gt;Cosmic blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>career</category>
    </item>
    <item>
      <title>Build a Blog with Next.js 16 and Cosmic CMS</title>
      <dc:creator>Tony Spiro</dc:creator>
      <pubDate>Mon, 04 May 2026 18:52:56 +0000</pubDate>
      <link>https://dev.to/tonyspiro/build-a-blog-with-nextjs-16-and-cosmic-cms-5c9j</link>
      <guid>https://dev.to/tonyspiro/build-a-blog-with-nextjs-16-and-cosmic-cms-5c9j</guid>
      <description>&lt;p&gt;Next.js 16 shipped in October 2025 with Turbopack stable, React Compiler support, Cache Components, and a redesigned caching model. If you are starting a new blog or content site today, this is the stack to use.&lt;/p&gt;

&lt;p&gt;This tutorial walks you through building a production-ready blog from scratch using Next.js 16 and &lt;a href="https://www.cosmicjs.com?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=build-a-blog-nextjs-16" rel="noopener noreferrer"&gt;Cosmic&lt;/a&gt; as your headless CMS. You will set up a content model in Cosmic, fetch posts with the TypeScript SDK, render them in Next.js 16 App Router server components, and deploy to Vercel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Estimated time: 30 minutes&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Will Build
&lt;/h2&gt;

&lt;p&gt;A blog with a homepage listing posts, individual post pages, and tag filtering — all powered by Cosmic's REST API and the TypeScript SDK.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 20+&lt;/li&gt;
&lt;li&gt;A free &lt;a href="https://app.cosmicjs.com/signup?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=build-a-blog-nextjs-16" rel="noopener noreferrer"&gt;Cosmic account&lt;/a&gt; (no credit card required)&lt;/li&gt;
&lt;li&gt;A Vercel account for deployment (free tier is fine)&lt;/li&gt;
&lt;li&gt;Basic familiarity with React and TypeScript&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Create Your Cosmic Bucket
&lt;/h2&gt;

&lt;p&gt;Log into Cosmic and create a new bucket. Go to Object Types and create a new type called &lt;code&gt;blog-posts&lt;/code&gt;. Add the following metafields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;title&lt;/code&gt; — Text (built-in)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;slug&lt;/code&gt; — Text (built-in, auto-generated)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;content&lt;/code&gt; — Markdown (long-form post body)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;excerpt&lt;/code&gt; — Textarea (short summary, 160 chars max)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cover_image&lt;/code&gt; — File (featured image)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;published_date&lt;/code&gt; — Date&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tags&lt;/code&gt; — Text (comma-separated)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create 2-3 sample blog posts and publish them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Scaffold a Next.js 16 App
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-next-app@latest my-blog
&lt;span class="nb"&gt;cd &lt;/span&gt;my-blog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted: use the App Router, TypeScript, and Tailwind CSS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install the Cosmic TypeScript SDK
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @cosmicjs/sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure Environment Variables
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;.env.local&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;COSMIC_BUCKET_SLUG&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your-bucket-slug&lt;/span&gt;
&lt;span class="py"&gt;COSMIC_READ_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your-read-key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Create the Cosmic Client
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;lib/cosmic.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createBucketClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@cosmicjs/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createBucketClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;bucketSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_BUCKET_SLUG&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;readKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_READ_KEY&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Define Your TypeScript Types
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;types/post.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="nx"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="nx"&gt;cover_image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;imgix_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nl"&gt;published_date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Fetch Posts from Cosmic
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;lib/posts.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./cosmic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/types/post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getPosts&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;objects&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog-posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id,title,slug,metadata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-created_at&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;published&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;objects&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog-posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id,title,slug,metadata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;published&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Build the Homepage
&lt;/h2&gt;

&lt;p&gt;Replace &lt;code&gt;app/page.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getPosts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/lib/posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Image&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;revalidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;HomePage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPosts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max-w-3xl mx-auto py-12 px-4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-4xl font-bold mb-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Blog&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;space-y-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cover_image&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Image&lt;/span&gt;
                &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cover_image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imgix_url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?w=800&amp;amp;auto=format`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rounded-lg mb-4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-2xl font-semibold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/blog/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Link&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-gray-600 mt-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/article&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 7: Build the Individual Post Page
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;app/blog/[slug]/page.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getPosts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getPost&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/lib/posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactMarkdown&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-markdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateStaticParams&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPosts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PostPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;  &lt;span class="c1"&gt;// Next.js 16: params is a Promise&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max-w-3xl mx-auto py-12 px-4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-4xl font-bold mb-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ReactMarkdown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ReactMarkdown&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important Next.js 16 note:&lt;/strong&gt; &lt;code&gt;params&lt;/code&gt; in dynamic route pages is now a &lt;code&gt;Promise&lt;/code&gt;. You must &lt;code&gt;await params&lt;/code&gt; before accessing its properties. This is a breaking change from Next.js 14.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 8: On-Demand Revalidation
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;app/api/revalidate/route.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;revalidatePath&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-cosmic-secret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_WEBHOOK_SECRET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unauthorized&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;revalidatePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/blog/[slug]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;revalidatePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;revalidated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Cosmic, go to Bucket Settings &amp;gt; Webhooks and add a webhook pointing to your &lt;code&gt;/api/revalidate&lt;/code&gt; endpoint. Trigger it on publish events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 9: Deploy to Vercel
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx vercel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or push to GitHub and import at vercel.com. Add your environment variables in Vercel's dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 10: Preview Mode for Drafts (Bonus)
&lt;/h2&gt;

&lt;p&gt;Enable draft previews by setting &lt;code&gt;status: 'any'&lt;/code&gt; on the Cosmic client for preview routes. Wire this up to Next.js Draft Mode for a live editor preview experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Built
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Next.js 16 blog with App Router and server components&lt;/li&gt;
&lt;li&gt;Content managed in Cosmic (no database required)&lt;/li&gt;
&lt;li&gt;Static generation with ISR for fast page loads&lt;/li&gt;
&lt;li&gt;On-demand revalidation via webhooks&lt;/li&gt;
&lt;li&gt;Automatic image optimization via Cosmic's imgix CDN&lt;/li&gt;
&lt;li&gt;Deployed to Vercel in minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Cosmic for Next.js 16
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Sub-100ms API responses&lt;/em&gt; — Cosmic's CDN caches content globally, keeping TTFB low at high traffic&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Structured content model&lt;/em&gt; — your schema maps cleanly to TypeScript interfaces&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;No backend to maintain&lt;/em&gt; — Cosmic handles hosting, scaling, and backups&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Free tier to start&lt;/em&gt; — 1 bucket, 1,000 objects, 100K cached API requests/month, no credit card required&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://app.cosmicjs.com/signup?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=build-a-blog-nextjs-16" rel="noopener noreferrer"&gt;Sign up for Cosmic free&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cosmicjs.com/docs" rel="noopener noreferrer"&gt;Check the Cosmic documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://calendly.com/tonyspiro/cosmic-intro" rel="noopener noreferrer"&gt;Book a demo with Tony&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>cms</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How We Built AI Agents Into a Headless CMS</title>
      <dc:creator>Tony Spiro</dc:creator>
      <pubDate>Tue, 28 Apr 2026 22:13:43 +0000</pubDate>
      <link>https://dev.to/tonyspiro/how-we-built-ai-agents-into-a-headless-cms-1l3g</link>
      <guid>https://dev.to/tonyspiro/how-we-built-ai-agents-into-a-headless-cms-1l3g</guid>
      <description>&lt;p&gt;Most AI features in a CMS are cosmetic. Autocomplete here. A "generate with AI" button there. Useful, sure, but they don't change how teams actually work.&lt;/p&gt;

&lt;p&gt;We wanted to go further. We wanted the CMS to have its own team.&lt;/p&gt;

&lt;p&gt;This post is a technical walkthrough of how we built four specialized AI agents directly into Cosmic, how they communicate, what they can actually do, and how you can chain them together into fully automated workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem We Were Solving
&lt;/h2&gt;

&lt;p&gt;Every content team we talked to had a version of the same story: someone needed a page updated, a blog post published, or a feature shipped, and it was stuck in a queue. Not because anyone was lazy. Because developer time is finite and content operations compete with product work.&lt;/p&gt;

&lt;p&gt;The answer wasn't a better editor. It was removing the dependency entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Four Agent Types
&lt;/h2&gt;

&lt;p&gt;Cosmic ships with four purpose-built agent types. Each one is optimized for a specific domain.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Team Agent
&lt;/h3&gt;

&lt;p&gt;The Team Agent lives in your messaging tools: Slack, WhatsApp, and Telegram. You define its persona, give it a goal, and it communicates with your team like a real colleague. Under the hood, it maintains persistent conversation memory, understands context across sessions, and can trigger actions in the CMS, your codebase, or third-party APIs based on natural language instructions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example use case:&lt;/strong&gt; A content team member messages the agent in Slack: "Write a blog post about our new integration with Vercel and publish it as a draft for review." The Team Agent delegates to the Content Agent, monitors execution, and reports back in the thread.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Content Agent
&lt;/h3&gt;

&lt;p&gt;The Content Agent is a CMS-native worker. It can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Research topics by browsing the web&lt;/li&gt;
&lt;li&gt;Generate text, images, and structured content&lt;/li&gt;
&lt;li&gt;Create and update CMS objects&lt;/li&gt;
&lt;li&gt;Auto-publish or queue content for human review&lt;/li&gt;
&lt;li&gt;Run on a schedule or be triggered via webhook&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It operates against your existing content models, so it understands your schema, your object types, and your metadata structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Code Agent
&lt;/h3&gt;

&lt;p&gt;The Code Agent connects to your GitHub repository and can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read the full file tree and specific files&lt;/li&gt;
&lt;li&gt;Write new features or fix bugs in your codebase&lt;/li&gt;
&lt;li&gt;Commit changes to branches&lt;/li&gt;
&lt;li&gt;Open pull requests automatically&lt;/li&gt;
&lt;li&gt;Respond to code-related tasks described in plain language&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where things get interesting for developer teams. A PM can say "add a newsletter signup form to the homepage" and the Code Agent will find the right files, write the component, create the content model in Cosmic to save newsletter subscribers, commit it, and open a PR for review.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Computer Use Agent
&lt;/h3&gt;

&lt;p&gt;The Computer Use Agent operates a real browser using visual AI. It can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate websites and interact with UI elements&lt;/li&gt;
&lt;li&gt;Record demo videos&lt;/li&gt;
&lt;li&gt;Extract structured data from any page&lt;/li&gt;
&lt;li&gt;Cross-post media between platforms&lt;/li&gt;
&lt;li&gt;Run visual QA on deployed pages&lt;/li&gt;
&lt;li&gt;Fill out and submit forms with dynamic input handling&lt;/li&gt;
&lt;li&gt;Authenticate into protected areas using secure login flows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the agent type that most surprises people. It's not scraping HTML, it's actually looking at the screen and clicking things, the same way a human would.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chaining Agents Into Workflows
&lt;/h2&gt;

&lt;p&gt;The real power comes when you chain agents together. Cosmic Workflows let you build multi-step automations that run in sequence or parallel, on a schedule or triggered by a webhook.&lt;/p&gt;

&lt;p&gt;Here's an example workflow for launching an e-commerce site:&lt;/p&gt;

&lt;p&gt;Traditional timeline for this: 2 to 3 weeks. With Cosmic Workflows: approximately 20 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical Architecture
&lt;/h2&gt;

&lt;p&gt;A few implementation details worth knowing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;REST API.&lt;/strong&gt; All agent interactions with the CMS go through Cosmic's REST API, which returns responses in under 100ms. The TypeScript SDK wraps the API cleanly, and the CLI and MCP Server give agents additional surfaces to work with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Framework-agnostic.&lt;/strong&gt; The agents don't care what frontend you're using. They've been tested against Next.js, React, Vue, Nuxt, Astro, Remix, and Svelte.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scheduling and webhooks.&lt;/strong&gt; Content Agents and Workflows can be set to run on a cron schedule or triggered via incoming webhook. This means you can wire them into any external event: a new Stripe payment, a GitHub push, a form submission.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory modes.&lt;/strong&gt; Team Agents support both session memory (reset per conversation) and persistent memory (retained across all conversations). Persistent memory is what makes a Team Agent feel like an actual team member over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Looks Like In Practice
&lt;/h2&gt;

&lt;p&gt;FINN, the car subscription platform, has been using Cosmic to reduce their dependency on developer time for content changes. Their co-founder put it clearly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Cosmic is: us never having to ask a developer to change anything on the backend of our website." - Maximilian Wuhr, Co-Founder at FINN&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With agents, that same principle extends to code, QA, and content operations, running autonomously around the clock.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Cosmic is free to start, no credit card required.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free:&lt;/strong&gt; $0/month - 1 Bucket, 2 team members, 1,000 Objects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Builder:&lt;/strong&gt; $49/month - 2 Buckets, 3 team members, 5,000 Objects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team:&lt;/strong&gt; $299/month - 3 Buckets, 5 team members, 20,000 Objects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business:&lt;/strong&gt; $499/month - 5 Buckets, 10 team members, 50,000 Objects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can explore the agents and workflows at &lt;a href="https://www.cosmicjs.com/ai" rel="noopener noreferrer"&gt;cosmicjs.com/ai&lt;/a&gt;. If you want to talk through what this could look like for your specific stack, &lt;a href="https://calendly.com/tonyspiro/cosmic-intro" rel="noopener noreferrer"&gt;book a quick call with Tony&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>cms</category>
      <category>webdev</category>
      <category>ai</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Cosmic Agents vs Sanity Agent Context vs Hygraph AI: A Real Comparison</title>
      <dc:creator>Tony Spiro</dc:creator>
      <pubDate>Mon, 27 Apr 2026 18:25:04 +0000</pubDate>
      <link>https://dev.to/tonyspiro/cosmic-agents-vs-sanity-agent-context-vs-hygraph-ai-a-real-comparison-1fmk</link>
      <guid>https://dev.to/tonyspiro/cosmic-agents-vs-sanity-agent-context-vs-hygraph-ai-a-real-comparison-1fmk</guid>
      <description>&lt;p&gt;The phrase "AI-powered CMS" has become meaningless. Every headless CMS vendor is using it. The real question is: what does the AI actually do?&lt;/p&gt;

&lt;p&gt;Cosmic, Sanity, and Hygraph are three of the most actively developed headless CMS platforms in 2026. All three are investing in AI. But their approaches are categorically different, and the distinction matters for how you build.&lt;/p&gt;

&lt;p&gt;This comparison looks at what each platform's AI actually does, where it stops, and which approach fits what kind of team.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We're Comparing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cosmic:&lt;/strong&gt; Four distinct agent types (Team, Content, Code, Computer Use) that operate across your entire stack&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sanity Agent Context:&lt;/strong&gt; A structured content delivery layer for external AI agents, plus the Content Agent for content operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hygraph:&lt;/strong&gt; AI-assisted content features (generation, translation, enrichment) built into the editorial workflow, with no native agent product&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not equivalent products doing the same thing at different price points. They represent three distinct philosophies about where AI belongs in a content platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cosmic: Agents That Work Across Your Stack
&lt;/h2&gt;

&lt;p&gt;Cosmic ships four agent types that operate at different layers of your development workflow:&lt;/p&gt;

&lt;h3&gt;
  
  
  Team Agents
&lt;/h3&gt;

&lt;p&gt;Live in Slack, WhatsApp, and Telegram. They have persistent memory, custom personas, and configurable goals. A Team Agent can be your content lead, a growth assistant, a support agent, or anything else your team needs. They participate in your actual communication channels, receive messages, respond to them, and maintain context across conversations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content Agents
&lt;/h3&gt;

&lt;p&gt;Generate and manage CMS content: blog posts, landing pages, AI images, AI video. They run on schedules, respond to webhooks, and chain into multi-step workflows. A Content Agent can publish a weekly roundup, generate product descriptions at scale, or update metadata across hundreds of objects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Agents
&lt;/h3&gt;

&lt;p&gt;Connect directly to GitHub repositories. They create branches, commit code, build features, fix bugs, and open pull requests. A Code Agent can receive a feature request in Slack and deliver a working pull request to your repository. This is not a content tool. It is a software development tool built into a CMS platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Computer Use Agents
&lt;/h3&gt;

&lt;p&gt;Control browsers using visual AI. They record demo videos, extract data from web pages, cross-post media, and automate any browser-based workflow.&lt;/p&gt;

&lt;p&gt;All four agent types chain together in Workflows. A single workflow can: generate content with a Content Agent, build a feature in GitHub with a Code Agent, and test the result with a Computer Use Agent.&lt;/p&gt;

&lt;p&gt;The key distinction: Cosmic agents are not features inside a CMS dashboard. They are autonomous team members that operate across your content, codebase, and communication channels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sanity: Agent Context + Content Agent
&lt;/h2&gt;

&lt;p&gt;Sanity's AI story has two distinct parts worth separating.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent Context
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.sanity.io/agent-context" rel="noopener noreferrer"&gt;Agent Context&lt;/a&gt; is Sanity's framework for making your CMS content available to external AI agents via MCP. It provides semantic search, GROQ + semantic query combination, editorial access controls, and real-time sync.&lt;/p&gt;

&lt;p&gt;Agent Context is infrastructure for other people's agents to use your Sanity content. It is not Sanity building agents that act on your behalf.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content Agent
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.sanity.io/content-agent" rel="noopener noreferrer"&gt;Sanity's Content Agent&lt;/a&gt; is focused on content operations inside the CMS: bulk edits across thousands of documents, content audits, bulk replace across large document sets, and web search to identify content gaps.&lt;/p&gt;

&lt;p&gt;The scope: Sanity's Content Agent stays inside the CMS. It does not write application code, touch your GitHub repository, create branches, open pull requests, or deploy software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hygraph: AI Features, Not AI Agents
&lt;/h2&gt;

&lt;p&gt;Hygraph offers AI-assisted content features built into the editorial and content operations workflow. There is no dedicated Hygraph AI agent product.&lt;/p&gt;

&lt;p&gt;What Hygraph does with AI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Content enhancement: AI writing assistance, SEO optimization, metadata generation&lt;/li&gt;
&lt;li&gt;Translation and localization: AI-powered translation with integrations like DeepL&lt;/li&gt;
&lt;li&gt;Workflow automation: AI enrichment triggered by content changes via Agent Actions&lt;/li&gt;
&lt;li&gt;Content auditing: Find stale pages, missing metadata, terminology drift&lt;/li&gt;
&lt;li&gt;Federation: Query distributed content sources in real time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What Hygraph does not have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native AI agents that act autonomously on your behalf&lt;/li&gt;
&lt;li&gt;Code agents that work in GitHub&lt;/li&gt;
&lt;li&gt;Team agents that live in Slack or messaging channels&lt;/li&gt;
&lt;li&gt;Multi-agent workflows that chain content, code, and browser automation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Side-by-Side: What Each Platform's AI Actually Does
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Cosmic&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Team agents in Slack, WhatsApp, Telegram: Yes&lt;/li&gt;
&lt;li&gt;Content generation and management agents: Yes&lt;/li&gt;
&lt;li&gt;Code agents (GitHub branches, PRs, commits): Yes&lt;/li&gt;
&lt;li&gt;Computer Use / browser automation agents: Yes&lt;/li&gt;
&lt;li&gt;Multi-agent chained Workflows: Yes&lt;/li&gt;
&lt;li&gt;MCP Server: Yes (17 tools)&lt;/li&gt;
&lt;li&gt;Agent Skills for Cursor, Claude Code, Copilot: Yes (16+ integrations)&lt;/li&gt;
&lt;li&gt;Bulk content operations via AI: Yes&lt;/li&gt;
&lt;li&gt;AI image generation: Yes&lt;/li&gt;
&lt;li&gt;AI video generation: Yes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Sanity&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Team agents in messaging channels: Slack only (via Content Agent)&lt;/li&gt;
&lt;li&gt;Content generation and management agents: Yes (Content Agent)&lt;/li&gt;
&lt;li&gt;Code agents (GitHub branches, PRs, commits): No&lt;/li&gt;
&lt;li&gt;Computer Use / browser automation agents: No&lt;/li&gt;
&lt;li&gt;Multi-agent chained Workflows: No&lt;/li&gt;
&lt;li&gt;MCP Server: Yes&lt;/li&gt;
&lt;li&gt;Bulk content operations via AI: Yes (Content Agent's core strength)&lt;/li&gt;
&lt;li&gt;AI image generation: Yes (via Content Agent)&lt;/li&gt;
&lt;li&gt;AI video generation: No&lt;/li&gt;
&lt;li&gt;Structured content delivery for external agents (Agent Context): Yes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hygraph&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Team agents in messaging channels: No&lt;/li&gt;
&lt;li&gt;Content generation and management agents: No (AI-assisted features, not agents)&lt;/li&gt;
&lt;li&gt;Code agents (GitHub branches, PRs, commits): No&lt;/li&gt;
&lt;li&gt;Computer Use / browser automation agents: No&lt;/li&gt;
&lt;li&gt;Multi-agent chained Workflows: No&lt;/li&gt;
&lt;li&gt;MCP Server: No dedicated product&lt;/li&gt;
&lt;li&gt;Bulk content operations via AI: Yes (via Agent Actions, event-driven)&lt;/li&gt;
&lt;li&gt;AI translation (field-by-field): Yes&lt;/li&gt;
&lt;li&gt;AI content auditing: Yes&lt;/li&gt;
&lt;li&gt;Content federation for AI use cases: Yes (a genuine differentiator)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Practical Question: What Layer Do You Need AI to Operate In?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Choose Cosmic if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want AI that operates across your full stack: content, code, browser, and communication channels&lt;/li&gt;
&lt;li&gt;Your team needs Code Agents creating branches and opening pull requests automatically&lt;/li&gt;
&lt;li&gt;You want AI team members living in Slack, WhatsApp, or Telegram with persistent memory&lt;/li&gt;
&lt;li&gt;Multi-agent Workflows that chain content generation, code deployment, and browser testing matter to you&lt;/li&gt;
&lt;li&gt;You use Cursor, Claude Code, or GitHub Copilot and want your CMS context built into your IDE's AI assistant&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Choose Sanity if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your primary AI use case is managing large volumes of existing content through conversation&lt;/li&gt;
&lt;li&gt;You need bulk editing, content audits, and gap analysis across thousands of documents&lt;/li&gt;
&lt;li&gt;Your team is editorial-first and the bottleneck is content operations, not engineering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Choose Hygraph if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your priority is AI-assisted content workflows inside a governed, enterprise content platform&lt;/li&gt;
&lt;li&gt;Federation across distributed content sources is a real architectural need&lt;/li&gt;
&lt;li&gt;You need field-level AI translation with schema integrity for a global content operation&lt;/li&gt;
&lt;li&gt;You prefer AI that stays in an assisted, human-reviewed loop&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pricing Comparison (Verified April 2026)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Cosmic&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Free: $0/month, 1 Bucket, 2 Team members, 1,000 Objects, 1 Team agent&lt;/li&gt;
&lt;li&gt;Builder: $49/month, 2 Buckets, 3 Team members, 5,000 Objects, 3 Team agents&lt;/li&gt;
&lt;li&gt;Team: $299/month, 3 Buckets, 5 Team members, 20,000 Objects, 10 Team agents&lt;/li&gt;
&lt;li&gt;Business: $499/month, 5 Buckets, 10 Team members, 50,000 Objects, 25 Team agents&lt;/li&gt;
&lt;li&gt;Additional users: $29/user/month&lt;/li&gt;
&lt;li&gt;Free plan is genuinely free forever, no credit card required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Sanity&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Free: $0/month, up to 20 seats, 10,000 documents&lt;/li&gt;
&lt;li&gt;Growth: $15/seat/month, up to 50 seats, 25,000 documents&lt;/li&gt;
&lt;li&gt;Enterprise: Custom&lt;/li&gt;
&lt;li&gt;Notable: Dedicated support is a $799/month add-on. SSO is $1,399/month.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hygraph&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Free tier available&lt;/li&gt;
&lt;li&gt;Scale and Enterprise tiers (contact for pricing)&lt;/li&gt;
&lt;li&gt;Federation and advanced AI features are enterprise-tier&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Deeper Distinction: Infrastructure vs. Agents
&lt;/h2&gt;

&lt;p&gt;Sanity's Agent Context takes a real infrastructure play: instead of building agents, they are making Sanity the best content source for whatever agents you or your users are building.&lt;/p&gt;

&lt;p&gt;Cosmic's bet is different. The agents are not features on top of the CMS. They are the product. Cosmic's position is that the CMS of 2026 is not a place where humans store content and developers build on top of it. It is an agentic platform where AI team members participate in the full development and content lifecycle.&lt;/p&gt;

&lt;p&gt;As FINN co-founder Maximilian Wuhr put it: "Cosmic is: us never having to ask a developer to change anything on the backend of our website."&lt;/p&gt;

&lt;p&gt;That is one version of what agents unlock. The ceiling is much higher.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does Hygraph have AI agents?&lt;/strong&gt;&lt;br&gt;
Not in the autonomous sense. Hygraph offers AI-assisted content features and event-driven AI enrichment via Agent Actions. There is no Hygraph agent that acts independently across your stack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Sanity Agent Context?&lt;/strong&gt;&lt;br&gt;
Agent Context is Sanity's infrastructure layer that makes your Sanity content available to external AI agents via MCP. It is not Sanity building agents on your behalf.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can Cosmic agents write code?&lt;/strong&gt;&lt;br&gt;
Yes. Cosmic Code Agents connect to GitHub repositories, create branches, commit changes, and open pull requests. This is one of the core distinctions from both Sanity's and Hygraph's AI offerings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is Cosmic free?&lt;/strong&gt;&lt;br&gt;
Yes. Cosmic's Free plan is $0/month forever, no credit card required. It includes 1 Bucket, 2 Team members, 1,000 Objects, and 1 Team agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready to See Cosmic Agents in Action?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://app.cosmicjs.com/signup" rel="noopener noreferrer"&gt;Start free, no credit card required&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://calendly.com/tonyspiro/cosmic-intro" rel="noopener noreferrer"&gt;Book a demo with Tony&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cosmicjs.com/docs" rel="noopener noreferrer"&gt;Explore the docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cosmicjs.com/marketplace/agents" rel="noopener noreferrer"&gt;Browse agent templates&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cms</category>
      <category>ai</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Why Headless CMS Is the Wrong Category</title>
      <dc:creator>Tony Spiro</dc:creator>
      <pubDate>Sun, 26 Apr 2026 23:17:54 +0000</pubDate>
      <link>https://dev.to/tonyspiro/why-headless-cms-is-the-wrong-category-n1e</link>
      <guid>https://dev.to/tonyspiro/why-headless-cms-is-the-wrong-category-n1e</guid>
      <description>&lt;p&gt;The term "headless CMS" made sense in 2015. It was a genuine breakthrough: decouple your content from your presentation layer, expose it through an API, and let developers build whatever frontend they wanted. It solved a real problem.&lt;/p&gt;

&lt;p&gt;In 2026, calling a platform like Cosmic a "headless CMS" is like calling Vercel a "file host." Technically not wrong. Strategically, completely wrong.&lt;/p&gt;

&lt;p&gt;The category has moved. The label hasn't. It's time to name what comes next.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Original Headless CMS Promise (And Why It Was Right for Its Time)
&lt;/h2&gt;

&lt;p&gt;Around 2013 to 2016, the web development world hit a wall. WordPress powered a third of the internet, but it also chained content to PHP templates and a rigid frontend. Enterprise teams were stuck in Sitecore and Adobe Experience Manager, paying six-figure licensing fees for systems that required specialists just to publish a blog post.&lt;/p&gt;

&lt;p&gt;Headless CMS changed the contract. Content lived in a structured repository, accessible via API. Developers could build frontends in React, Vue, Angular, or anything else they chose. Content teams could work independently in a clean editor. The decoupling was real and valuable.&lt;/p&gt;

&lt;p&gt;Platforms like Contentful (founded 2013) and later Sanity, Storyblok, and Prismic built strong businesses on this premise. The market validated them. According to Grand View Research, the headless CMS market is worth $2 to $4 billion today and is projected to grow to $6 billion or more by 2033.&lt;/p&gt;

&lt;p&gt;The problem is not that headless CMS failed. The problem is that it succeeded, and then the world kept moving.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. What Developer Teams Actually Need in 2026
&lt;/h2&gt;

&lt;p&gt;Talk to any engineering lead at a modern product company and ask them what they need from their content infrastructure. You will not hear "a better API for structured content." You will hear something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We need our marketing team to launch new landing pages without filing a Jira ticket.&lt;/li&gt;
&lt;li&gt;We need our AI agents to be able to read and write content programmatically.&lt;/li&gt;
&lt;li&gt;We need our content workflows to trigger downstream actions: Slack notifications, data syncs, deployment pipelines.&lt;/li&gt;
&lt;li&gt;We need our editors to work in Slack or WhatsApp, not a separate dashboard.&lt;/li&gt;
&lt;li&gt;We need our platform to handle the full lifecycle: create, publish, personalize, and retire content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a content management problem. It is a content infrastructure problem. And content infrastructure in 2026 looks nothing like a headless CMS from 2016.&lt;/p&gt;

&lt;p&gt;The broader composable content and modern CMS market is estimated at $10 to $25 billion by MarketsandMarkets. Teams that limit their thinking to "headless CMS" are scoping themselves into a shrinking corner of a much larger map.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The Category Convergence Happening Right Now
&lt;/h2&gt;

&lt;p&gt;Something interesting is happening across the developer tools landscape. The clean category lines that existed five years ago are dissolving.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CMS platforms are becoming dev platforms. Contentful launched an app framework. Sanity built a structured content operating system. Storyblok added visual editing.&lt;/li&gt;
&lt;li&gt;Dev platforms are becoming content platforms. Vercel launched CMS integrations. Netlify acquired multiple CMS products. Cloudflare Pages added content workflows.&lt;/li&gt;
&lt;li&gt;AI tooling is collapsing into both. Large language models need structured content to stay grounded. AI agents need APIs to read and write content programmatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result: every serious platform is building toward the same destination. The companies that still describe themselves primarily by their 2016 category name are telling you something about their product roadmap thinking.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Why the Wrong Category Label Is Costing Teams Money and Time
&lt;/h2&gt;

&lt;p&gt;This is not just a semantics debate. Category labels drive buying decisions, and wrong labels create wrong criteria.&lt;/p&gt;

&lt;p&gt;When a CTO goes to evaluate a "headless CMS," they bring a headless CMS checklist: API performance, content modeling flexibility, editor experience, pricing per seat. Legitimate criteria. But incomplete for 2026.&lt;/p&gt;

&lt;p&gt;They are not asking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can AI agents in my team's Slack channel query and update this content without a human in the loop?&lt;/li&gt;
&lt;li&gt;Can I build a full internal tool or customer-facing app on this platform, not just a marketing site?&lt;/li&gt;
&lt;li&gt;Does this platform have an MCP Server so tools like Claude Code and Cursor can work directly with my content?&lt;/li&gt;
&lt;li&gt;Can I extend the platform with Agent Skills, so my editors can trigger complex workflows from a chat interface?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When teams do not ask these questions, they end up buying a headless CMS and then separately buying an AI platform, a workflow tool, an internal tooling framework, and a handful of Zapier integrations to stitch it all together. The category label caused them to under-scope the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. What the New Category Looks Like
&lt;/h2&gt;

&lt;p&gt;The new category does not have a consensus name yet. Here is what it includes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content infrastructure.&lt;/strong&gt; Structured content models, a fast REST API and TypeScript SDK, global CDN delivery, media management. The table stakes headless CMS established. Still necessary, but no longer sufficient.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI-native agents.&lt;/strong&gt; Not AI bolted on top of a content editor. AI agents that are first-class members of your team. They live in Slack, WhatsApp, and Telegram. They can read content, write content, trigger workflows, and respond to natural language requests. They operate on schedules or respond to events.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workflow automation.&lt;/strong&gt; Multi-step automated processes that chain content operations, approvals, notifications, and external API calls into coherent pipelines. Native workflow execution, not a third-party integration layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developer-first extensibility.&lt;/strong&gt; An MCP Server that lets AI coding tools like Claude Code and Cursor interact directly with your content infrastructure. Agent Skills that make content operations available as composable building blocks for any AI assistant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App platform capabilities.&lt;/strong&gt; The ability to build not just content-driven websites but full applications on the same infrastructure. Content becomes data. The CMS becomes the backend.&lt;/p&gt;

&lt;p&gt;This is not a feature list. It is a different mental model for what a content platform is.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Where Cosmic Fits in the New Map
&lt;/h2&gt;

&lt;p&gt;Cosmic (YC W19) started as a headless CMS. It has the API performance, the content modeling, and the editor experience that enterprises require. Companies like FINN, Tripwire Interactive, Parque Explora, and Vuetify chose it and stayed because the fundamentals are solid.&lt;/p&gt;

&lt;p&gt;FINN's co-founder Maximilian Wuhr put it directly: "Cosmic is: us never having to ask a developer to change anything on the backend of our website."&lt;/p&gt;

&lt;p&gt;That outcome, non-technical teams operating independently, is the original headless CMS promise fulfilled.&lt;/p&gt;

&lt;p&gt;But Cosmic has not stopped there. Today, Cosmic is an AI-powered content and app platform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI Agents in Slack, WhatsApp, and Telegram.&lt;/strong&gt; Editors can request content, trigger updates, and get summaries without leaving their messaging app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workflows.&lt;/strong&gt; Multi-step automated pipelines that orchestrate content operations, approvals, and integrations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Server.&lt;/strong&gt; AI coding tools like Claude Code and Cursor can interact directly with your content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent Skills for Cursor and Claude Code.&lt;/strong&gt; Composable content operations available natively to the AI tools your developers already use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;REST API and TypeScript SDK.&lt;/strong&gt; Battle-tested, fast, and developer-friendly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The market segment Cosmic competes in is not a $4 billion headless CMS market. It is a $25 billion-plus content infrastructure and AI-powered app platform market.&lt;/p&gt;

&lt;p&gt;Calling it a headless CMS is like calling Vercel a file host. Accurate at the edges. Completely wrong about what it is.&lt;/p&gt;




&lt;p&gt;The category will be named. We're naming it now.&lt;/p&gt;

&lt;p&gt;An Agentic Content Platform is not a headless CMS with AI bolted on. It is a platform where AI agents are first-class participants in every content operation: writing, editing, publishing, coding, deploying, measuring.&lt;/p&gt;

&lt;p&gt;The companies that recognize this shift early will stop evaluating "headless CMS vendors" and start asking a different question: which platform lets my team move fastest when humans and agents are working together?&lt;/p&gt;

&lt;p&gt;That is the question Cosmic is built to answer.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Ready to see what AI-powered content infrastructure looks like? &lt;a href="https://app.cosmicjs.com/signup" rel="noopener noreferrer"&gt;Start free on Cosmic&lt;/a&gt; or &lt;a href="https://calendly.com/tonyspiro/cosmic-intro" rel="noopener noreferrer"&gt;book a demo&lt;/a&gt; to talk through what your stack could look like.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>cms</category>
      <category>ai</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to Migrate from Storyblok to Cosmic</title>
      <dc:creator>Tony Spiro</dc:creator>
      <pubDate>Sun, 26 Apr 2026 23:11:31 +0000</pubDate>
      <link>https://dev.to/tonyspiro/how-to-migrate-from-storyblok-to-cosmic-4e10</link>
      <guid>https://dev.to/tonyspiro/how-to-migrate-from-storyblok-to-cosmic-4e10</guid>
      <description>&lt;p&gt;A step-by-step guide for developers migrating from Storyblok to Cosmic: content model mapping, component-to-metafield conversion, media migration, API migration, and webhooks — with real TypeScript code examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Developers Are Migrating from Storyblok to Cosmic
&lt;/h2&gt;

&lt;p&gt;Storyblok was a smart choice for teams who wanted a visual editor baked into their CMS. But as applications grow in complexity and AI becomes central to content operations, its limitations become harder to work around. Three pain points keep coming up in migration conversations:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual editor lock-in.&lt;/strong&gt; Storyblok components are built around page presentation, which couples your content model to your frontend. When you need to reuse content across channels, that coupling becomes a bottleneck.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pricing pressure.&lt;/strong&gt; Seat fees, delivery limits, and add-on costs compound as teams grow. Budgeting for Storyblok at scale is unpredictable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No native AI.&lt;/strong&gt; Adding AI to a Storyblok workflow requires third-party integrations and significant custom engineering. Cosmic has AI Agents built in.&lt;/p&gt;

&lt;p&gt;If any of those sound familiar, this guide will walk you through the full migration process: content model mapping, component-to-metafield conversion, media migration, API migration, and webhooks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before You Start: Understanding the Key Differences
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Storyblok Concept&lt;/th&gt;
&lt;th&gt;Cosmic Equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Story&lt;/td&gt;
&lt;td&gt;Object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Component/Block&lt;/td&gt;
&lt;td&gt;Object Type + Metafields&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Component Field&lt;/td&gt;
&lt;td&gt;Metafield&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Space&lt;/td&gt;
&lt;td&gt;Bucket&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Asset&lt;/td&gt;
&lt;td&gt;Media&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Datasource&lt;/td&gt;
&lt;td&gt;Object Type (for structured reference data)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Webhook&lt;/td&gt;
&lt;td&gt;Webhook (via add-on)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The most important conceptual shift: Storyblok organizes content around components on stories. Cosmic organizes content around Objects of a given Object Type. The result is more flexible — you're not constrained by what a visual editor can preview.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Map Your Content Model
&lt;/h2&gt;

&lt;p&gt;Start by auditing your Storyblok components. For each component, you'll create a corresponding Object Type in Cosmic with the right Metafields.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Field type mapping reference:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storyblok &lt;code&gt;richtext&lt;/code&gt; → Cosmic &lt;code&gt;html-textarea&lt;/code&gt; or &lt;code&gt;markdown&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Storyblok &lt;code&gt;asset&lt;/code&gt; → Cosmic &lt;code&gt;file&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Storyblok &lt;code&gt;text&lt;/code&gt; → Cosmic &lt;code&gt;text&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Storyblok &lt;code&gt;textarea&lt;/code&gt; → Cosmic &lt;code&gt;textarea&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Storyblok single select → Cosmic &lt;code&gt;select&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Storyblok multi select → Cosmic &lt;code&gt;multi-select&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Storyblok nested blocks → Cosmic relationship field or &lt;code&gt;objects&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Storyblok reference → Cosmic relationship field (&lt;code&gt;object&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 2: Export Your Content from Storyblok
&lt;/h2&gt;

&lt;p&gt;Use the Storyblok Management API to export your stories. You'll need your Storyblok API token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;`https://mapi.storyblok.com/v1/spaces/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;SPACE_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/stories`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;STORYBLOK_MANAGEMENT_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stories&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Migrate Media Assets
&lt;/h2&gt;

&lt;p&gt;Before importing content objects, migrate your media. Storyblok stores assets on their CDN; you'll need to re-upload them to Cosmic's media library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createBucketClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@cosmicjs/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createBucketClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;bucketSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_BUCKET_SLUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;readKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_READ_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;writeKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_WRITE_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;migrateAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storyblokUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storyblokUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;media&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;media&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;media&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;media&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imgix_url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Import Content to Cosmic
&lt;/h2&gt;

&lt;p&gt;With your content model mapped and media migrated, import your stories as Cosmic Objects using the JavaScript/TypeScript SDK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;importStory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;story&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StoryblokStory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mediaMap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;story&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-object-type-slug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;story&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;published&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;published&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;draft&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;story&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mediaMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;story&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// map other fields as needed&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Update Your API Calls
&lt;/h2&gt;

&lt;p&gt;Storyblok and Cosmic have different API patterns. Here's how to update your frontend code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (Storyblok):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;storyblokInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;apiPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storyblok/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;storyblokInit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STORYBLOK_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;apiPlugin&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;storyblokApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cdn/stories&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;published&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (Cosmic):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createBucketClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@cosmicjs/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createBucketClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;bucketSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_BUCKET_SLUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;readKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_READ_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;objects&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-object-type-slug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id,title,slug,metadata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Cosmic uses the REST API only. There is no GraphQL endpoint.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 6: Migrate Webhooks
&lt;/h2&gt;

&lt;p&gt;If you use Storyblok webhooks to trigger builds or revalidation, you'll need to set up Cosmic webhooks. Cosmic webhooks are available as an add-on ($99/month, or included in the $199/month bundle). Once enabled, configure them in the Cosmic dashboard under Settings &amp;gt; Webhooks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migration Checklist
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Content Model&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Audit all Storyblok components and fields&lt;/li&gt;
&lt;li&gt;[ ] Create corresponding Object Types in Cosmic dashboard&lt;/li&gt;
&lt;li&gt;[ ] Map all field types (richtext → markdown, asset → file, etc.)&lt;/li&gt;
&lt;li&gt;[ ] Test Object Type schemas with sample content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Media&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Export list of all Storyblok assets&lt;/li&gt;
&lt;li&gt;[ ] Run media migration script&lt;/li&gt;
&lt;li&gt;[ ] Verify asset URLs in Cosmic media library&lt;/li&gt;
&lt;li&gt;[ ] Build asset URL map for content import&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Content&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Export all Storyblok stories via Management API&lt;/li&gt;
&lt;li&gt;[ ] Run content import script&lt;/li&gt;
&lt;li&gt;[ ] Verify published/draft status is correct&lt;/li&gt;
&lt;li&gt;[ ] Spot-check content in Cosmic dashboard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;API Integration&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Replace Storyblok SDK imports with Cosmic SDK&lt;/li&gt;
&lt;li&gt;[ ] Update all API calls to use Cosmic REST API&lt;/li&gt;
&lt;li&gt;[ ] Update environment variables&lt;/li&gt;
&lt;li&gt;[ ] Test all content queries in development&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Webhooks and Automation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Recreate Storyblok webhooks in Cosmic&lt;/li&gt;
&lt;li&gt;[ ] Update webhook endpoints in your applications&lt;/li&gt;
&lt;li&gt;[ ] Test build triggers and cache revalidation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Go Live&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Run full content audit comparing Storyblok and Cosmic&lt;/li&gt;
&lt;li&gt;[ ] Update DNS / CDN configuration if needed&lt;/li&gt;
&lt;li&gt;[ ] Monitor error rates after launch&lt;/li&gt;
&lt;li&gt;[ ] Deprecate Storyblok account once migration is confirmed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Supported Frameworks
&lt;/h2&gt;

&lt;p&gt;Cosmic works with all major JavaScript frameworks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js&lt;/strong&gt; — Full support including App Router and Pages Router&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt; — Works with any React setup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vue&lt;/strong&gt; — Full compatibility&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nuxt&lt;/strong&gt; — Server-side rendering and static generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Astro&lt;/strong&gt; — Content collections and SSR&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remix&lt;/strong&gt; — Loader-based data fetching&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Svelte / SvelteKit&lt;/strong&gt; — Full support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gatsby&lt;/strong&gt; — Static generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Cosmic JavaScript/TypeScript SDK works in any Node.js environment and in modern browsers.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published on the &lt;a href="https://www.cosmicjs.com/blog/migrate-from-storyblok-to-cosmic" rel="noopener noreferrer"&gt;Cosmic blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>cms</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Headless CMS for TanStack Start: Build a Blog with Cosmic</title>
      <dc:creator>Tony Spiro</dc:creator>
      <pubDate>Sat, 18 Apr 2026 19:08:53 +0000</pubDate>
      <link>https://dev.to/tonyspiro/headless-cms-for-tanstack-start-build-a-blog-with-cosmic-k6f</link>
      <guid>https://dev.to/tonyspiro/headless-cms-for-tanstack-start-build-a-blog-with-cosmic-k6f</guid>
      <description>&lt;p&gt;You want SSR, fast routing, and a CMS your whole team can edit without touching code. Here's how to build that stack in under an hour.&lt;/p&gt;

&lt;p&gt;TanStack Start pairs naturally with Cosmic: Start handles full-document SSR, streaming, and type-safe routing via Vite and TanStack Router, while Cosmic gives you a structured, API-first content layer your editors can use without a developer in the room. The result is a modern content stack that's fast to build, easy to maintain, and genuinely pleasant to work with.&lt;/p&gt;

&lt;p&gt;This tutorial walks through building a content-driven TanStack Start blog powered by Cosmic. You'll fetch posts from Cosmic using the JavaScript SDK, render them with server functions, and have a working SSR blog in under 30 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 18 or later&lt;/li&gt;
&lt;li&gt;A free &lt;a href="https://app.cosmicjs.com/signup" rel="noopener noreferrer"&gt;Cosmic account&lt;/a&gt; with a bucket set up&lt;/li&gt;
&lt;li&gt;Basic familiarity with React and TypeScript&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Create a TanStack Start Project
&lt;/h2&gt;

&lt;p&gt;The fastest way to scaffold a new project is with the TanStack CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-tsrouter-app@latest my-cosmic-app &lt;span class="nt"&gt;--template&lt;/span&gt; start-basic
&lt;span class="nb"&gt;cd &lt;/span&gt;my-cosmic-app
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you a working TanStack Start app with file-based routing, SSR enabled, and Vite as the bundler.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Install the Cosmic SDK
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @cosmicjs/sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Configure Your Environment Variables
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file at the root of your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;COSMIC_BUCKET_SLUG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-bucket-slug
&lt;span class="nv"&gt;COSMIC_READ_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-read-key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find both values in your Cosmic dashboard under &lt;em&gt;Bucket &amp;gt; Settings &amp;gt; API Keys&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TanStack Start uses Vite under the hood. Server-side environment variables are accessed via &lt;code&gt;process.env&lt;/code&gt; inside server functions. For client-side access, prefix with &lt;code&gt;VITE_&lt;/code&gt; — but keep your read key on the server only.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  4. Create a Cosmic Client
&lt;/h2&gt;

&lt;p&gt;Add a shared client file at &lt;code&gt;src/lib/cosmic.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createBucketClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@cosmicjs/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createBucketClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;bucketSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_BUCKET_SLUG&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;readKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COSMIC_READ_KEY&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Fetch Posts with a Server Function
&lt;/h2&gt;

&lt;p&gt;TanStack Start's server functions run exclusively on the server, making them the right place to call external APIs and keep keys out of the client bundle.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;src/server/posts.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createServerFn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tanstack/start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../lib/cosmic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;teaser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="na"&gt;published_date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;imgix_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchPosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServerFn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;objects&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog-posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metadata.teaser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metadata.published_date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metadata.image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;objects&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchPost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServerFn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validator&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cosmic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog-posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metadata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Create the Blog Index Route
&lt;/h2&gt;

&lt;p&gt;TanStack Start uses file-based routing. Create &lt;code&gt;src/routes/blog/index.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createFileRoute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tanstack/react-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fetchPosts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../server/posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createFileRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/blog/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)({&lt;/span&gt;
  &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fetchPosts&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BlogIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BlogIndex&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useLoaderData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max-w-2xl mx-auto py-12 px-4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-3xl font-bold mb-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Blog&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;space-y-6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt;
              &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/blog/$slug&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
              &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;group&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-xl font-semibold group-hover:underline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;teaser&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-gray-600 mt-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;teaser&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="p"&gt;)}&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;published_date&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-sm text-gray-400&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;published_date&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLocaleDateString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/time&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Link&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Create the Post Detail Route
&lt;/h2&gt;

&lt;p&gt;Install &lt;code&gt;react-markdown&lt;/code&gt; for safe, component-based markdown rendering:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;react-markdown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;src/routes/blog/$slug.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createFileRoute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;notFound&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tanstack/react-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactMarkdown&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-markdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fetchPost&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../server/posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createFileRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/blog/$slug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)({&lt;/span&gt;
  &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchPost&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nf"&gt;notFound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BlogPost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BlogPost&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useLoaderData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max-w-2xl mx-auto py-12 px-4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;imgix_url&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;
          &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imgix_url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?w=800&amp;amp;auto=format`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;w-full rounded-lg mb-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-3xl font-bold mb-4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;published_date&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-sm text-gray-400 block mb-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;published_date&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLocaleDateString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/time&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prose&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ReactMarkdown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;markdown_content&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ReactMarkdown&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  8. Run the Dev Server
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;http://localhost:3000/blog&lt;/code&gt; and you should see your Cosmic posts rendered server-side via TanStack Start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy to Vercel
&lt;/h2&gt;

&lt;p&gt;TanStack Start supports Vercel out of the box. From the project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; vercel
vercel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your environment variables in the Vercel dashboard under &lt;em&gt;Project &amp;gt; Settings &amp;gt; Environment Variables&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;COSMIC_BUCKET_SLUG&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;COSMIC_READ_KEY&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Deploy and you're live.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Build Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Localization:&lt;/em&gt; Cosmic's Localization add-on lets you manage content in multiple languages from the same bucket. Add a &lt;code&gt;locale&lt;/code&gt; param to your SDK calls and TanStack Router handles the rest.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Webhooks:&lt;/em&gt; Trigger a Vercel redeploy automatically when editors publish new content in Cosmic. Set up a webhook in Cosmic pointing to your Vercel deploy hook URL.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Team Agent in Slack:&lt;/em&gt; Install a Cosmic Team Agent in your Slack workspace. Editors can publish, update, and query content from Slack without opening the dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Full-text search:&lt;/em&gt; Use the Cosmic REST API with a &lt;code&gt;?query=&lt;/code&gt; parameter to add search to your TanStack Start app without a separate search service.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Cosmic is an AI-powered headless CMS with a REST API, TypeScript SDK, and AI agents that live in Slack, WhatsApp, and Telegram. &lt;a href="https://app.cosmicjs.com/signup" rel="noopener noreferrer"&gt;Start for free&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>tanstack</category>
      <category>cosmicjs</category>
      <category>react</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
