Skip to content

useflytrap/notion-contentlayer

Repository files navigation

Notion contentlayer cover

Notion Contentlayer

npm version npm downloads Github Actions

Type-safe Notion contentlayer to easily build Notion-backed blogs, changelogs and more

Notion Contentlayer is a type-safe solution for easily fetching and rendering Notion content. Content is transformed to MDAST, so you can easily integrate with the Remark and Rehype ecosystem. Read more →

Features

  • Runtime & type-safe way to consume Notion page properties.
  • Versatile renderer for MDAST content. Learn more →
  • Integrates with Remark & Rehype ecosystem. Learn more →

⚡️ Quickstart

  1. Install the Notion contentlayer package
$ npm install notion-contentlayer
  1. Setup a Notion database for your content

Hello World

How do I find my API key and table ID?

TODO: Write it up

  1. Create Notion source
import { createNotionSource, url, people, checkbox, text, date, select, status, title } from "notion-contentlayer"
import { Client } from "@notionhq/client"

const notionClient = new Client({
  auth: process.env.NOTION_API_KEY,
})

const notionSource = createNotionSource({
  properties: {
    cover: url("Image"),
    authors: people("Authors"),
    isFeatured: checkbox("Featured"),
    slug: text("Slug"),
    publishedDate: date("Date"),
    isPublished: checkbox("Published"),
    description: text("Description"),
    category: select("Category"),
    status: status("Status"),
    featuredCover: text("FeaturedImage"),
    title: title("Page"),
  },
  client: notionClient,
  databaseId: process.env.NOTION_TABLE_ID as string,
})
  1. Consume the content

All notion-contentlayer functions have Rust-inspired error handling built-in, so you don't need to try / catch anything. Just consume as below.

// 👇 `content`: true fetches the content for each blog post
const postResult = await notionSource.fetchPosts({ content: true })
//    ^^^^^^^^^^ postResult is a `Result`

if (postResult.isErr()) {
  // Render error state
  console.error(postResult.error)
  return
}

const posts = postResult.value;
/*
import type { Root } from "mdast"

`posts` is of type:
type Posts = {
  cover: string
  authors: User[]
  isFeatured: boolean
  slug: string
  publishedDate: Date
  isPublished: boolean
  category: string
  status: string
  featuredCover: string
  title: string
  blocks: Root
}[]
*/

🎥 Versatile renderer for MDAST

TODO Write Docs

⛓️ Integrate with Remark & Rehype

Since notion-contentlayer transforms all Notion blocks into a MDAST, you can perfectly integrate with the Remark and Rehype ecosystem.

Here's an example of how to use it to render HTML

const notionClient = new Client({
  auth: process.env.NOTION_API_KEY,
})

const notionSource = createNotionSource({
  // your options
})

const mdastResult = await notionSource.getPostContents('post-id-123')
if (mdastResult.isErr()) {
  console.error(mdastResult.error)
  return
}

const file = await unified()
  .use(remarkParse)
  .use(remarkGfm)
  .use(remarkRehype)
  .use(rehypeStringify)
  .process(mdastResult.value)

console.log(String(file))
// => "<h1>Notion example</h1><h2>Autolink literals</h2> ..."

💻 Development

  • Clone this repository
  • Enable Corepack using corepack enable (use npm i -g corepack for Node.js < 16.10)
  • Install dependencies using pnpm install
  • Run the tests using pnpm dev

License

Made with ❤️ in Helsinki, Finland.

Published under MIT License.