Documentation Index Fetch the complete documentation index at: https://buttercms.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
Overview
This integration guide shows you how to how to update your existing project to:
install the ButterCMS package
instantiate ButterCMS
create components to fetch and display each of the three ButterCMS content types: Pages , Collections , and Blog Posts .
Starter project
Or, you can jump directly to the starter project below, which will allow you to clone, install, run, and deploy a fully working
starter project that’s integrated with content already inside of your ButterCMS account.
Astro Starter Project Hit the ground running with a pre-configured Astro + ButterCMS setup.
Installation
Add your API token to .env:
BUTTER_CMS_API_KEY = your_api_token
Initialize the client
Create a reusable client instance:
// src/lib/buttercms.ts
import Butter from 'buttercms' ;
const butter = Butter ( import . meta . env . BUTTER_CMS_API_KEY );
export default butter ;
For complete SDK documentation including all available methods and configuration options, see the JavaScript SDK Reference .
Pages
Static (SSG)
Server (SSR)
---
// src/pages/[slug].astro
import butter from '../lib/buttercms' ;
export async function getStaticPaths () {
const response = await butter . page . list ( 'landing-page' );
return response . data . data . map (( page ) => ({
params: { slug: page . slug },
props: { page },
}));
}
interface Props {
page : {
fields : {
headline : string ;
subheadline : string ;
hero_image : string ;
body : string ;
};
};
}
const { page } = Astro . props ;
---
< main >
< h1 > { page . fields . headline } </ h1 >
< p > { page . fields . subheadline } </ p >
{ page . fields . hero_image && (
< img src = { page . fields . hero_image } alt = { page . fields . headline } />
) }
< div set:html = { page . fields . body } />
</ main >
Enable SSR in astro.config.mjs: // astro.config.mjs
import { defineConfig } from 'astro/config' ;
export default defineConfig ({
output: 'server' , // or 'hybrid' for selective SSR
}) ;
---
// src/pages/[slug].astro
import butter from '../lib/buttercms' ;
const { slug } = Astro . params ;
let page ;
try {
const response = await butter . page . retrieve ( 'landing-page' , slug );
page = response . data . data ;
} catch {
return Astro . redirect ( '/404' );
}
---
< main >
< h1 > { page . fields . headline } </ h1 >
< p > { page . fields . subheadline } </ p >
{ page . fields . hero_image && (
< img src = { page . fields . hero_image } alt = { page . fields . headline } />
) }
< div set:html = { page . fields . body } />
</ main >
Collections
---
// src/pages/brands.astro
import butter from '../lib/buttercms' ;
interface Brand {
name : string ;
logo : string ;
description : string ;
}
const response = await butter . content . retrieve ([ 'brands' ]);
const brands : Brand [] = response . data . data . brands ;
---
< main >
< h1 > Our Brands </ h1 >
< ul >
{ brands . map (( brand ) => (
< li >
< img src = { brand . logo } alt = { brand . name } />
< h2 > { brand . name } </ h2 >
< div set : html = { brand . description } />
</ li >
)) }
</ ul >
</ main >
Dynamic components
Component Renderer
---
// src/components/ComponentRenderer.astro
import Hero from './Hero.astro' ;
import Features from './Features.astro' ;
import Testimonials from './Testimonials.astro' ;
import CTA from './CTA.astro' ;
interface Props {
components : Array <{
type : string ;
fields : Record < string , any >;
}>;
}
const { components } = Astro . props ;
const componentMap = {
hero: Hero ,
features: Features ,
testimonials: Testimonials ,
cta: CTA ,
};
---
{ components . map (( component ) => {
const Component = componentMap [ component . type ];
return Component ? < Component { ... component . fields } /> : null ;
}) }
Example Component
---
// src/components/Hero.astro
interface Props {
headline : string ;
subheadline : string ;
image : string ;
button_label : string ;
button_url : string ;
}
const { headline , subheadline , image , button_label , button_url } = Astro . props ;
---
< section class = "hero" >
< h1 > { headline } </ h1 >
< p > { subheadline } </ p >
{ button_label && < a href = { button_url } > { button_label } </ a > }
{ image && < img src = { image } alt = { headline } /> }
</ section >
Using in Pages
---
// src/pages/landing/[slug].astro
import butter from '../../lib/buttercms' ;
import ComponentRenderer from '../../components/ComponentRenderer.astro' ;
export async function getStaticPaths () {
const response = await butter . page . list ( 'landing-page' );
return response . data . data . map (( page ) => ({
params: { slug: page . slug },
props: { page },
}));
}
const { page } = Astro . props ;
---
< main >
< ComponentRenderer components = { page . fields . body } />
</ main >
Blog
Blog Post List
Single Blog Post
---
// src/pages/blog/index.astro
import butter from '../../lib/buttercms' ;
interface Post {
slug : string ;
title : string ;
summary : string ;
author : { first_name : string ; last_name : string };
}
const response = await butter . post . list ({ page: 1 , page_size: 10 });
const posts : Post [] = response . data . data ;
const meta = response . data . meta ;
---
< main >
< h1 > Blog </ h1 >
< ul >
{ posts . map (( post ) => (
< li >
< h2 >< a href = { `/blog/ ${ post . slug } ` } > { post . title } </ a ></ h2 >
< p set : html = { post . summary } />
< span > By { post . author . first_name } { post . author . last_name } </ span >
</ li >
)) }
</ ul >
{ meta . next_page && (
< a href = { `/blog/page/ ${ meta . next_page } ` } > Next Page </ a >
) }
</ main >
---
// src/pages/blog/[slug].astro
import butter from '../../lib/buttercms' ;
export async function getStaticPaths () {
const response = await butter . post . list ({ page_size: 100 });
return response . data . data . map (( post ) => ({
params: { slug: post . slug },
props: { post },
}));
}
interface Props {
post : {
title : string ;
body : string ;
published : string ;
featured_image : string ;
author : { first_name : string ; last_name : string };
};
}
const { post } = Astro . props ;
---
< article >
< h1 > { post . title } </ h1 >
< p >
By { post . author . first_name } { post . author . last_name } on { ' ' }
{new Date ( post . published ). toLocaleDateString () }
</ p >
{ post . featured_image && < img src = { post . featured_image } alt = { post . title } /> }
< div set:html = { post . body } />
< a href = "/blog" > Back to Posts </ a >
</ article >
Preview Mode
Enable draft content preview with SSR:
---
// src/pages/preview/[...slug].astro
import Butter from 'buttercms' ;
const butter = Butter ( import . meta . env . BUTTER_CMS_API_KEY , true ); // Enable preview mode
const { slug } = Astro . params ;
const [ pageType , pageSlug ] = slug . split ( '/' );
let page ;
try {
const response = await butter . page . retrieve ( pageType , pageSlug );
page = response . data . data ;
} catch {
return Astro . redirect ( '/404' );
}
---
< div class = "preview-banner" > Preview Mode </ div >
< main >
< h1 > { page . fields . headline } </ h1 >
< div set:html = { page . fields . body } />
</ main >
SEO
---
// src/pages/[slug].astro
import butter from '../lib/buttercms' ;
import Layout from '../layouts/Layout.astro' ;
export async function getStaticPaths () {
const response = await butter . page . list ( 'landing-page' );
return response . data . data . map (( page ) => ({
params: { slug: page . slug },
props: { page },
}));
}
const { page } = Astro . props ;
const seo = page . fields . seo || {};
---
< Layout
title = { seo . title || page . fields . headline }
description = { seo . description }
ogTitle = { seo . og_title || seo . title }
ogDescription = { seo . og_description || seo . description }
ogImage = { seo . og_image }
>
< main >
< h1 > { page . fields . headline } </ h1 >
< div set:html = { page . fields . body } />
</ main >
</ Layout >
Layout with SEO:
---
// src/layouts/Layout.astro
interface Props {
title : string ;
description ?: string ;
ogTitle ?: string ;
ogDescription ?: string ;
ogImage ?: string ;
}
const { title , description , ogTitle , ogDescription , ogImage } = Astro . props ;
---
< ! doctype html >
< html lang = "en" >
< head >
< meta charset = "UTF-8" />
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" />
< title > { title } </ title >
{ description && < meta name = "description" content = { description } /> }
{ ogTitle && < meta property = "og:title" content = { ogTitle } /> }
{ ogDescription && < meta property = "og:description" content = { ogDescription } /> }
{ ogImage && < meta property = "og:image" content = { ogImage } /> }
</ head >
< body >
< slot />
</ body >
</ html >
Resources
Astro Starter Pre-configured starter project
JavaScript SDK Complete SDK reference
GitHub Repository View source code
Content API REST API documentation