Skip to content
Blume
Esc
↑↓navigate↵open⌘Jpreview

Contentful

Read a Contentful content type through the Delivery API with the contentful() source, lowering rich text bodies to Markdown with nothing to install.

The built-in contentful() adapter reads the entries of one content type through the Content Delivery API and lowers each entry’s rich text body to Markdown: headings, marks, links, lists, quotes, tables, and embedded assets map to their Markdown equivalents, and a body held in a Markdown long-text field passes through as written, except that a link that isn’t a web, mail, phone, or relative address (a javascript: URL, say) keeps only its label, as it does in rich text. Nothing to install — the adapter speaks the REST API directly.

import { defineConfig } from "blume";
import { contentful, filesystem } from "blume/sources";

export default defineConfig({
  content: {
    sources: [
      filesystem({ root: "docs" }),
      contentful({
        prefix: "guides",
        space: "abc123",
        contentType: "guide",
        // environment: "master", locale: "en-US"
        // Field ids default to title / description / slug / body, and the
        // date to sys.updatedAt
        fields: { body: "content" },
        // Extra Delivery API query parameters
        params: { "fields.section": "sdk" },
      }),
    ],
  },
});

The Delivery API token comes from the CONTENTFUL_ACCESS_TOKEN environment variable, which the adapter declares. Under --preview the adapter reads drafts through the Preview API with CONTENTFUL_PREVIEW_TOKEN. The Preview API rejects delivery tokens, so --preview without a preview token fails with a clear error rather than falling back to CONTENTFUL_ACCESS_TOKEN. Assets are referenced from Contentful’s CDN rather than downloaded — their URLs are stable. An embedded entry maps to a Blume component through the engine’s serializers option, keyed by content type id, when you construct contentfulSource directly and pass it to custom(); setting serializers writes the source’s pages as MDX so the returned components render, and an embedded entry without a serializer is noted in a comment. A link to another entry renders as plain text, since there is no route to point at.

Last updated on September 27, 2026

Was this page helpful?