Skip to main content

Overview

This integration guide shows you how to how to update your existing project to:
  1. install the ButterCMS package
  2. instantiate ButterCMS
  3. 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.

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.

Gridsome Starter Project

Hit the ground running with a pre-configured Gridsome + ButterCMS setup.

Installation

npm install buttercms
Add your API token to .env:
BUTTERCMS_API_TOKEN=your_api_token

Initialize the client

Create a reusable client module:
// src/lib/buttercms.js
const Butter = require('buttercms');

const butter = Butter(process.env.BUTTERCMS_API_TOKEN);

module.exports = butter;
For complete SDK documentation including all available methods and configuration options, see the JavaScript SDK Reference.

Pages

Gridsome loads external data at build time via gridsome.server.js. Add a custom data source to fetch ButterCMS pages:
// gridsome.server.js
const butter = require('./src/lib/buttercms');

module.exports = function(api) {
  api.loadSource(async ({ addCollection }) => {
    const pagesCollection = addCollection('ButterPage');

    try {
      const response = await butter.page.list('landing-page', { page_size: 100 });
      const pages = response.data.data;

      pages.forEach((page) => {
        pagesCollection.addNode({
          id: page.slug,
          slug: page.slug,
          fields: page.fields,
        });
      });
    } catch (error) {
      console.error('Error fetching ButterCMS pages:', error);
    }
  });

  api.createPages(async ({ createPage, graphql }) => {
    const { data } = await graphql(`
      {
        allButterPage {
          edges {
            node {
              slug
            }
          }
        }
      }
    `);

    data.allButterPage.edges.forEach(({ node }) => {
      createPage({
        path: node.slug === 'home' ? '/' : `/page/${node.slug}`,
        component: './src/templates/LandingPage.vue',
        context: {
          slug: node.slug,
        },
      });
    });
  });
};
Create the page template:
<!-- src/templates/LandingPage.vue -->
<template>
  <Layout>
    <main v-if="$page.butterPage">
      <h1>{{ $page.butterPage.fields.headline }}</h1>
      <p>{{ $page.butterPage.fields.subheadline }}</p>
      <img
        v-if="$page.butterPage.fields.hero_image"
        :src="$page.butterPage.fields.hero_image"
        :alt="$page.butterPage.fields.headline"
      />
      <div v-html="$page.butterPage.fields.body" />
    </main>
  </Layout>
</template>

<page-query>
query LandingPage($slug: String!) {
  butterPage(slug: $slug) {
    slug
    fields {
      headline
      subheadline
      hero_image
      body
    }
  }
}
</page-query>

<script>
export default {
  metaInfo() {
    const page = this.$page.butterPage;
    if (!page) return {};
    const seo = page.fields.seo || {};
    return {
      title: seo.title || page.fields.headline,
      meta: [
        { name: 'description', content: seo.description },
      ],
    };
  },
};
</script>

Collections

Add your collections to the Gridsome data store:
// gridsome.server.js (add inside api.loadSource)
const brandsCollection = addCollection('ButterBrand');

try {
  const response = await butter.content.retrieve(['brands']);
  const brands = response.data.data.brands;

  brands.forEach((brand, index) => {
    brandsCollection.addNode({
      id: String(index),
      name: brand.name,
      logo: brand.logo,
      description: brand.description,
    });
  });
} catch (error) {
  console.error('Error fetching ButterCMS brands:', error);
}
Query and display collection items in a Vue component:
<!-- src/pages/Brands.vue -->
<template>
  <Layout>
    <main>
      <h1>Our Brands</h1>
      <ul>
        <li v-for="brand in $page.allButterBrand.edges" :key="brand.node.id">
          <img :src="brand.node.logo" :alt="brand.node.name" />
          <h2>{{ brand.node.name }}</h2>
          <div v-html="brand.node.description" />
        </li>
      </ul>
    </main>
  </Layout>
</template>

<page-query>
{
  allButterBrand {
    edges {
      node {
        id
        name
        logo
        description
      }
    }
  }
}
</page-query>

Dynamic components

Component Renderer

<!-- src/components/ComponentRenderer.vue -->
<template>
  <div>
    <component
      v-for="(item, index) in components"
      :key="index"
      :is="componentMap[item.type]"
      v-if="componentMap[item.type]"
      v-bind="item.fields"
    />
  </div>
</template>

<script>
import Hero from './Hero.vue';
import Features from './Features.vue';
import Testimonials from './Testimonials.vue';
import CTA from './CTA.vue';

export default {
  props: {
    components: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {
      componentMap: {
        hero: Hero,
        features: Features,
        testimonials: Testimonials,
        cta: CTA,
      },
    };
  },
};
</script>

Example Component

<!-- src/components/Hero.vue -->
<template>
  <section class="hero">
    <h1>{{ headline }}</h1>
    <p>{{ subheadline }}</p>
    <a v-if="button_label" :href="button_url" class="btn">{{ button_label }}</a>
    <img v-if="image" :src="image" :alt="headline" />
  </section>
</template>

<script>
export default {
  props: ['headline', 'subheadline', 'image', 'button_label', 'button_url'],
};
</script>

Using in templates

<!-- src/templates/ComponentPage.vue -->
<template>
  <Layout>
    <main v-if="$page.butterPage">
      <ComponentRenderer :components="$page.butterPage.fields.body" />
    </main>
  </Layout>
</template>

<page-query>
query($slug: String!) {
  butterPage(slug: $slug) {
    slug
    fields {
      body {
        type
        fields {
          headline
          subheadline
          image
          button_label
          button_url
        }
      }
    }
  }
}
</page-query>

<script>
import ComponentRenderer from '~/components/ComponentRenderer.vue';

export default {
  components: { ComponentRenderer },
};
</script>

Blog

Add blog posts to the data store in gridsome.server.js:
// gridsome.server.js (add inside api.loadSource)
const postsCollection = addCollection('ButterPost');

try {
  const response = await butter.post.list({ page_size: 100 });
  const posts = response.data.data;

  posts.forEach((post) => {
    postsCollection.addNode({
      id: post.slug,
      slug: post.slug,
      title: post.title,
      summary: post.summary,
      body: post.body,
      published: post.published,
      featured_image: post.featured_image,
      author: post.author,
    });
  });
} catch (error) {
  console.error('Error fetching ButterCMS posts:', error);
}

// Create blog post pages
api.createPages(async ({ createPage, graphql }) => {
  const { data } = await graphql(`
    {
      allButterPost {
        edges {
          node {
            slug
          }
        }
      }
    }
  `);

  data.allButterPost.edges.forEach(({ node }) => {
    createPage({
      path: `/blog/${node.slug}`,
      component: './src/templates/BlogPost.vue',
      context: { slug: node.slug },
    });
  });
});
<!-- src/pages/Blog.vue -->
<template>
  <Layout>
    <main>
      <h1>Blog</h1>
      <ul>
        <li v-for="post in $page.allButterPost.edges" :key="post.node.slug">
          <h2>
            <g-link :to="`/blog/${post.node.slug}`">{{ post.node.title }}</g-link>
          </h2>
          <p v-html="post.node.summary" />
          <span>
            By {{ post.node.author.first_name }} {{ post.node.author.last_name }}
          </span>
        </li>
      </ul>
    </main>
  </Layout>
</template>

<page-query>
{
  allButterPost(sortBy: "published", order: DESC) {
    edges {
      node {
        slug
        title
        summary
        published
        author {
          first_name
          last_name
        }
      }
    }
  }
}
</page-query>

Resources

Gridsome Starter

Pre-configured starter project

JavaScript SDK

Complete SDK reference

GitHub Repository

View source code

Content API

REST API documentation