🧑🏼🏭 Don't mind us, we are still working on this site using NotionCMS!
Like this project? Sponsor us on GitHub:
⚡️⚡️⚡️ Get Started ⚡️⚡️⚡️
const myCoolCMS = new NotionCMS({
databaseId: 'e4bce5b3-1d3a-4afd-b961-10d56cg436aj',
notionAPIKey: process.env.NOTION as string,
})
await myCoolCMS.pull()
const postA = myCoolCMS.data['/posts']['/how-to-build-a-blog-with-notion']
const postB = myCoolCMS.data['/posts']['/how-to-use-notion-cms']
const postC = myCoolCMS.data['/posts']['/how-to-make-a-million-with-notion-cms']
// html
postA.content.html
// markdown
postB.content.markdown
// plaintext
postC.content.plaintext
NotionCMS is a powerful server-land package that lets you leverage Notion as a full-fledged headless CMS. It does this by building a cacheable, serialized data tree from your Notion database. No more jumping through hoops to get your content out of Notion, just the rush of raw information at your fingertips.
Result
{
"metadata": {
"databaseId": "e4fcd5b3-1d6a-4afd-b951-10d56ce436ad",
},
"stages": [
"db",
"content",
"complete"
],
"routes": [
"/metal-detectors",
"/metal-detectorists",
"..."
],
"tags": [
"Lightweight",
"Fisher",
"..."
],
"tagGroups": {
"Lightweight": [
"/metal-detectors/fisher-f-44-metal-detector",
"/metal-detectors/teknetics-omega-8500-metal-detector",
"/metal-detectors/quest-x-5-detector",
"/metal-detectors/bounty-hunter-land-ranger-pro-metal-detector",
"/metal-detectors/teknetics-t-2-classic-metal-detector"
],
"Fisher": [
"/metal-detectors/fisher-f-44-metal-detector",
"/metal-detectors/fisher-gold-bug-2-metal-detector",
"/metal-detectors/fisher-f-75-metal-detector",
"/metal-detectors/hands-free-hunter"
],
},
"siteData": {
"/treasures": {
"_key": "/treasures",
"name": "treasures",
"slug": "treasures",
"authors": [],
"tags": [],
"path": "/treasures",
"url": "",
"content": {
html: "",
markdown: "",
plaintext: ""
},
"/a-cache-of-precious-gems": {
"name": "A cache of precious gems",
"slug": "a-cache-of-precious-gems",
"authors": [],
"tags": [],
"path": "/treasures/a-cache-of-precious-gems",
"url": "",
"content": {
html: "",
markdown: "",
plaintext: "" // plugins add other flavors!
}
}
}
}
}
Wanna see more? Open up your browser’s console and inspect the page
object. This shows the current page’s subset of the NotionCMS tree.
🧑🏼🚀
Note: ncms
doesn’t run on the client, so what you see in your console has been serialized on the server and sent client side with the rest of the client bundle.
🏗️ Framework agnostic - it’s just JS.
🌲 Build a collection-based CMS tree from your Notion database.
🎚️ Leverage database structure to control your routing structure.
⚙️ Geared for Static Site Generation.
📑 Transform Notion blocks → Markdown, plaintext, and (customizable) html.
🗃️ Optimized Content Caching for super fast builds.
🧩 Plugin capable with some powerful core plugins on the way ready to go.
🤯 Provide your own custom renderers for Notion blocks.
🦾 Tagging, filtering, path queries, and tree-walking utilities.
🔋 Syntax highlighting (highlightjs
) out of the box!
npm install -D @agency-kit/notion-cms
pnpm add -D @agency-kit/notion-cms
yarn add -dev @agency-kit/notion-cms
Notion is great for managing content and has an excellent API and SDK. However, leveraging Notion as a headless CMS in production can be challenging.
Until recently, Notion did not support sub-pages (sub-items in a database). As a result, most existing Notion-as-a-headless-CMS solutions cannot leverage this new feature, which is crucial for building a collection-based headless CMS.
Another obstacle is that pulling content from Notion can be time-consuming. Responses can take a few seconds, the API provides a lot of data to sift through, and multiple calls to different endpoints are required to go from the CMS database to the content for each page. All of this together results in a suboptimal developer experience when using a static site generator that often makes requests on each build.
NotionCMS addresses each of these issues and provides an excellent developer experience while using Notion as your headless content management system.
The Notion API SDK is a great tool and there are certainly times where you would want to use that directly instead of Notion CMS. Here are a few scenarios that may help you choose the best tool for the job. 🛠️
🔨
Use Notion API SDK when you need total control over the final data structure of content pulled from Notion.
🔧
Use NotionCMS when you can leverage a standardized data tree to keep your application logic simple.
🔨
Use Notion API SDK when your Notion content that you want to fetch lives in various places in Notion and isn’t organized in unified database structure.
🔧
Use NotionCMS when you have a single database that you want to use to define your website’s structure. Entries in your database might correspond to pages or collections of items that each make sense as a route in your website or application.
Starting from scratch and not sure how you want to structure your data? NotionCMS provides a great starting point for projects that is simple to scale as your project grows.
🔨
Use Notion API SDK when you want total control over the process of translating Notion API result blocks into your client’s content format of choice
🔧
Use NotionCMS when you want to benefit from a pre-existing pipeline for translating Notion API results to html or other formats using NotionCMS plugin ecosystem.
NotionCMS is really geared towards a server-side environment, so its intended usage is in Node js.
This is because pulling content from Notion (but really more generally) and rendering it on a client is both a poor experience for the end user and terrible for SEO. Even if you are building a SPA, you probably want to prerender it.
That’s what NotionCMS is built for, though there is an issue for opening the door for client side usage, so if you have a use case feel free to chime in there.
In order to use NotionCMS, you have to subscribe to a specific database structure with a few core properties.
Its an extremely generic design that gives you all the things you need for basic sites but lends flexibility for types of content other than the standard web page, blog post etc.
See the structure in this template https://cooked-shovel-3c3.notion.site/Community-e9fce377adb1425da8ac3ef3acef2bc2
The first step to using NotionCMS is to make a NotionAPI integration and grant the integration access to the Notion page where your database will be stored. You will need to make a copy of the template database (recommended) and then copy both the database ID and your Notion API key into your project (using something like env variables).
Here’s a tutorial for setting up the Notion integration since it’s an essential step.
// initialize
const myCoolCMS = new NotionCMS({
databaseId: 'e4fcd5b3-1d6a-4afd-b951-10d56ce436ad',
notionAPIKey: process.env.NOTION,
// Other options
})
// Pull down all Notion content
// fetch returns a promise with the siteData structure
await myCoolCMS.fetch()
// Access the routes here:
console.log(myCoolCMS.routes)
// Access the page content here:
console.log(myCoolCMS.data)
// Access paths like this:
const postA = myCoolCMS.data['/posts']['/how-to-build-a-blog-with-notion']
const postB = myCoolCMS.data['/posts']['/how-to-use-notion-cms']
🧑🚀
Tip: If you’re using NotionCMS for the first time, make sure that at least some of your pages have the Published
select set to Published, or use the draftMode
option or you won’t see any content after running pull
!
// returns an array of only child pages of a page looked up using the key.
myCMS.filterSubPages('/path-segment' /* or Page reference*/)
// returns page reference
myCMS.queryByPath('/full/path/to/page')
// Get tagged collections this way or by passing a single tag:
const tagged = myCoolCMS.getTaggedCollection(['blog', 'programming'])
// Walk through all nodes in the CMS tree and perform some action
myCoolCMS.walk(node => console.log(node.name, node.path))
//async walk
await myCoolCMS.asyncWalk(async node => await /* some async action*/)
// Export the CMS object
// uses cache location by default and exports an ugly but optimized cache
myCoolCMS.export()
// Export prettified CMS object, wherever you want.
myCoolCMS.export({pretty: true, path: './debug/my-cool-cms.json'})
// Import an exported CMS object
myCoolCMS.import(jsonCMS)
const myAdvancedCMS = new NotionCMS({
databaseId: 'e4fcd5b3-1d6a-4afd-b951-10d56ce436ad',
notionAPIKey: process.env.NOTION,
rootUrl: 'https://mycoolsite.com',
localCacheDirectory: './localcache/',
refreshTimeout: 'one hour', // Or a number, 60 * 1000 * 60
plugins: [customPlugin()],
})
await myAdvancedCMS.pull() // alias for fetch, both work the same.
See the full API reference here.
NotionCMS is designed to be highly extensible and supports a variety of plugins to help you streamline your workflows when building websites with content from Notion.. Whether you need to add custom logic to your templates, declare Vue components right in your Notion page, or integrate with third-party services, NotionCMS makes it easy to extend the functionality of your headless CMS. Check out the ➡️ Plugins page ⬅️ for more information on using existing plugins or the 🏗️ building your own plugins guide for creating custom workflows with NotionCMS.
we make notionware. 2023 \c\