Build markdown-based static sites with Notion.
- Use Notion to write and organize pages
- notion-markdown-cms syncto build a markdown repository
- run your favourite static site generator (VuePress, Docusaurus, Gatsby, ...)
Success! π
- uses the official Notion API only
- written in typescript/javascript
- renders page properties to frontmatter
- recursively traverses the Notion Block graph to include database pages, child pages
- renders an index file of all your pages so you can easily build Navs/Sidebars
The following Notion API block object types are supported:
| Block Type | Supported | Notes | 
|---|---|---|
| Paragraph | β Yes | |
| Heading1-3 | β Yes | |
| Callout | β Yes | |
| Quote | β Yes | |
| Bulleted List | β Yes | |
| Numbered List | β Yes | |
| To do | β Yes | |
| Toggle | β (Yes) | Toggle content is included, however the toggle header is not | 
| Code | β Yes | An html block starting with <!--notion-markdown-cms:raw-->is rendered as raw HTML and not as a fenced block | 
| Child Pages | β not planned | avoid, they don't mix well with clear site navigation | 
| Child Databases | β Yes | renders as table + including child pages, inline-only tables planned | 
| Embed | β Missing | unclear, might be undesireable for static sites | 
| Image | β (Yes) | captions not supported yet | 
| Video | β Missing | |
| File | β Missing | |
| β Missing | ||
| Bookmark | β Yes | use a caption as a link name | 
| Equation | β Missing | |
| Divider | β Yes | |
| Table Of Contents | β not planned | static site generators have their own ToC implementations | 
| Breadcrumb | β not planned | static site generators have their own nav implementations | 
| Synced Block | β Yes | renders all children blocks | 
Support for other block types can be considered once they are available on the official Notion API.
The following Notion API rich text types are supported
| Rich Text Type | Supported | Notes | 
|---|---|---|
| Text | β Yes | |
| Mention | β partially | Page mentions only, mentioned pages are included | 
| Equation | β Missing | 
The following annotations (and any combination thereof) are supported:
| Annotation | Supported | Notes | 
|---|---|---|
| bold | β Yes | |
| italic | β Yes | |
| strikethrough | β Yes | |
| underline | β Yes | |
| code | β Yes | |
| color | β not planned | not available in markdown | 
The following Notion API page property types are supported
| Propety type | Supported | Notes | 
|---|---|---|
| Rich text | β Yes | rendered as plaintext string | 
| Number | β Yes | |
| Select | β Yes | rendered as name | 
| Multi Select | β Yes | rendered as array of names | 
| Date | β Yes | rendered as string | 
| Formula | β missing | |
| Relation | β Yes | rendered as array of page ids | 
| Rollup | β missing | |
| Title | β Yes | used as page title | 
| People | β Yes | rendered as comma-separated list of names | 
| Files | β missing | |
| Checkbox | β missing | |
| Url | β Yes | rendered as string | 
| β Yes | rendered as string | |
| Phone Number | β Yes | rendered as string | 
| Created time | β Yes | rendered as string | 
| Created by | β Yes | rendered as name | 
| Last edited time | β Yes | rendered as string | 
| Last edited by | β Yes | rendered as name | 
At the moment notion-markdown-cms is meant to be consumed via its node.js API from build scripts
wrapping your favourite static site generator tool. You can install it from npm
npm add "@meshcloud/notion-markdown-cms"You can find an example build script using the node.js API below. Consult the SyncConfig reference for documentation of available configuration options.
A CLI tool could be made available later.
import { slugify, SyncConfig, sync } from "notion-markdown-cms";
const config: SyncConfig = {
  cmsDatabaseId: "8f1de8c578fb4590ad6fbb0dbe283338",
  pages: {
    destinationDirBuilder: (page) => slugify(page.properties.get("Category")),
    frontmatterBuilder: (page) => ({
      id: page.meta.id,
      url: page.meta.url,
      title: page.meta.title,
      category: page.properties.get("Category")
    }),
  },
  databases: {
    "fe9836a9-6557-4f17-8adb-a93d2584f35f": {
      sorts: [
        {
          property: "Scope",
          direction: "ascending",
        },
        {
          property: "Cluster",
          direction: "ascending",
        },
      ],
      renderAs: "pages+views",
      pages: {
        destinationDirBuilder: (page) => slugify(page.properties.get("Scope")),
        frontmatterBuilder: (page) => ({
          id: page.meta.id,
          url: page.meta.url,
          title: page.meta.title,
          cluster: page.properties.get("Cluster")
        }),
      },
      views: [
      {
        title: "By Scope",
        properties: {
          groupBy: "Scope",
          include: ["Name", "Scope", "Cluster", "Summary"],
        },
      },
    },
  },
};
async function main() {
  const notionApiToken = process.env.NOTION_API_TOKEN;
  if (!notionApiToken) {
    throw new Error(
      "Required NOTION_API_TOKEN environment variable not provided."
    );
  }
  rimraf.sync("docs/!(README.md)**/*");
  // change into the docs dir, this simplifies handling relative paths
  process.chdir("docs/");
  const rendered = await sync(notionApiToken, config);
  // do something with the rendered index, e.g. writing it to a file or building a nav structure
}
main().catch((e) => {
  console.error(e);
  process.exit(1);
});There are quite a few alternatives out there already, so why did we build notion-markdown-cms?
Below table, albeit subjective, tries to answer this.
| Project | Notion API | Language | Rendering Engine | Output looks like | 
|---|---|---|---|---|
| Nortion Markdown CMS | β official | TypeScript | Markdown + JS Index | Site generator theme | 
| Notion2GitHub | Python | Markdown | Site generator theme | |
| notion-cms | TypeScript | React | Notion App | |
| vue-notion | JavaScript | Vue.js | Notion App | |
| react-notion | JavaScript | React | Notion App | 
For convenient development you can use
- nix-shellto set up a development environemnt
- You'll need a Notion database for testing. You can e.g. copy one of these to your own Notion Workspace
- A Notion API Token
As this project is still in its very early stages,
notion-markdown-cmsdoes not come with its own demo, example or test cases yet.