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.
In order for the snippets to work, you’ll need to setup your dashboard content schemas inside of ButterCMS first.
Installation
- npm
- yarn
- pnpm
npm install buttercms
yarn add buttercms
pnpm add buttercms
.env:
BUTTER_CMS_API_KEY=your_api_token
Initialize the client
Create a reusable client instance:// src/lib/buttercms.ts
import Butter from 'buttercms';
import { BUTTER_CMS_API_KEY } from '$env/static/private';
const butter = Butter(BUTTER_CMS_API_KEY);
export default butter;
For complete SDK documentation including all available methods and configuration options, see the JavaScript SDK Reference.
Pages
- Server-Side (SSR)
- Static (SSG)
// src/routes/[slug]/+page.server.ts
import butter from '$lib/buttercms';
import { error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ params }) => {
try {
const response = await butter.page.retrieve('landing-page', params.slug);
return { page: response.data.data };
} catch {
throw error(404, 'Page not found');
}
};
<!-- src/routes/[slug]/+page.svelte -->
<script lang="ts">
import type { PageData } from './$types';
export let data: PageData;
</script>
<main>
<h1>{data.page.fields.headline}</h1>
<p>{data.page.fields.subheadline}</p>
{#if data.page.fields.hero_image}
<img src={data.page.fields.hero_image} alt={data.page.fields.headline} />
{/if}
{@html data.page.fields.body}
</main>
Enable prerendering:
// src/routes/[slug]/+page.server.ts
import butter from '$lib/buttercms';
import { error } from '@sveltejs/kit';
import type { PageServerLoad, EntryGenerator } from './$types';
export const prerender = true;
export const entries: EntryGenerator = async () => {
const response = await butter.page.list('landing-page');
return response.data.data.map((page) => ({ slug: page.slug }));
};
export const load: PageServerLoad = async ({ params }) => {
try {
const response = await butter.page.retrieve('landing-page', params.slug);
return { page: response.data.data };
} catch {
throw error(404, 'Page not found');
}
};
Collections
// src/routes/brands/+page.server.ts
import butter from '$lib/buttercms';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async () => {
const response = await butter.content.retrieve(['brands']);
return { brands: response.data.data.brands };
};
<!-- src/routes/brands/+page.svelte -->
<script lang="ts">
import type { PageData } from './$types';
export let data: PageData;
</script>
<main>
<h1>Our Brands</h1>
<ul>
{#each data.brands as brand}
<li>
<img src={brand.logo} alt={brand.name} />
<h2>{brand.name}</h2>
{@html brand.description}
</li>
{/each}
</ul>
</main>
Dynamic components
Component Renderer
<!-- src/lib/components/ComponentRenderer.svelte -->
<script lang="ts">
import Hero from './Hero.svelte';
import Features from './Features.svelte';
import Testimonials from './Testimonials.svelte';
import CTA from './CTA.svelte';
import type { ComponentType } from 'svelte';
interface ButterComponent {
type: string;
fields: Record<string, any>;
}
export let components: ButterComponent[];
const componentMap: Record<string, ComponentType> = {
hero: Hero,
features: Features,
testimonials: Testimonials,
cta: CTA,
};
</script>
{#each components as component}
{#if componentMap[component.type]}
<svelte:component this={componentMap[component.type]} {...component.fields} />
{/if}
{/each}
Example Component
<!-- src/lib/components/Hero.svelte -->
<script lang="ts">
export let headline: string;
export let subheadline: string;
export let image: string;
export let button_label: string;
export let button_url: string;
</script>
<section class="hero">
<h1>{headline}</h1>
<p>{subheadline}</p>
{#if button_label}
<a href={button_url}>{button_label}</a>
{/if}
{#if image}
<img src={image} alt={headline} />
{/if}
</section>
Using in Pages
<!-- src/routes/landing/[slug]/+page.svelte -->
<script lang="ts">
import type { PageData } from './$types';
import ComponentRenderer from '$lib/components/ComponentRenderer.svelte';
export let data: PageData;
</script>
<main>
<ComponentRenderer components={data.page.fields.body} />
</main>
Blog
- Blog Post List
- Single Blog Post
// src/routes/blog/+page.server.ts
import butter from '$lib/buttercms';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ url }) => {
const page = parseInt(url.searchParams.get('page') || '1');
const response = await butter.post.list({ page, page_size: 10 });
return {
posts: response.data.data,
meta: response.data.meta,
};
};
<!-- src/routes/blog/+page.svelte -->
<script lang="ts">
import type { PageData } from './$types';
export let data: PageData;
</script>
<main>
<h1>Blog</h1>
<ul>
{#each data.posts as post}
<li>
<h2><a href="https://buttercms.com/blog/{post.slug}">{post.title}</a></h2>
{@html post.summary}
<span>By {post.author.first_name} {post.author.last_name}</span>
</li>
{/each}
</ul>
{#if data.meta.next_page}
<a href="/blog?page={data.meta.next_page}">Next Page</a>
{/if}
</main>
// src/routes/blog/[slug]/+page.server.ts
import butter from '$lib/buttercms';
import { error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ params }) => {
try {
const response = await butter.post.retrieve(params.slug);
return { post: response.data.data };
} catch {
throw error(404, 'Post not found');
}
};
<!-- src/routes/blog/[slug]/+page.svelte -->
<script lang="ts">
import type { PageData } from './$types';
export let data: PageData;
const formattedDate = new Date(data.post.published).toLocaleDateString();
</script>
<article>
<h1>{data.post.title}</h1>
<p>
By {data.post.author.first_name} {data.post.author.last_name} on {formattedDate}
</p>
{#if data.post.featured_image}
<img src={data.post.featured_image} alt={data.post.title} />
{/if}
{@html data.post.body}
<a href="/blog">Back to Posts</a>
</article>
Preview Mode
Enable draft content preview:// src/routes/preview/[...path]/+page.server.ts
import Butter from 'buttercms';
import { BUTTER_CMS_API_KEY } from '$env/static/private';
import { error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ params, url }) => {
const secret = url.searchParams.get('secret');
if (secret !== process.env.PREVIEW_SECRET) {
throw error(401, 'Invalid preview token');
}
const butter = Butter(BUTTER_CMS_API_KEY, true); // Enable preview mode
const [pageType, slug] = params.path.split('/');
try {
const response = await butter.page.retrieve(pageType, slug);
return { page: response.data.data, isPreview: true };
} catch {
throw error(404, 'Page not found');
}
};
SEO
<!-- src/routes/[slug]/+page.svelte -->
<script lang="ts">
import type { PageData } from './$types';
import { page } from '$app/stores';
export let data: PageData;
$: seo = data.page.fields.seo || {};
</script>
<svelte:head>
<title>{seo.title || data.page.fields.headline}</title>
{#if seo.description}
<meta name="description" content={seo.description} />
{/if}
<meta property="og:title" content={seo.og_title || seo.title || data.page.fields.headline} />
{#if seo.og_description || seo.description}
<meta property="og:description" content={seo.og_description || seo.description} />
{/if}
{#if seo.og_image}
<meta property="og:image" content={seo.og_image} />
{/if}
</svelte:head>
<main>
<h1>{data.page.fields.headline}</h1>
{@html data.page.fields.body}
</main>
Resources
JavaScript SDK
Complete SDK reference
Content API
REST API documentation