{"id":15059314,"url":"https://github.com/agency-kit/notion-cms","last_synced_at":"2025-04-10T05:23:12.651Z","repository":{"id":141917665,"uuid":"612792633","full_name":"agency-kit/notion-cms","owner":"agency-kit","description":"Add super powers to Notion by making it your full-fledged headless CMS.","archived":false,"fork":false,"pushed_at":"2024-02-12T06:31:07.000Z","size":869,"stargazers_count":41,"open_issues_count":26,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-04-03T17:42:01.845Z","etag":null,"topics":["cms","content","headless","headless-cms","jamstack","notion","notion-api","notion-blog","ssg"],"latest_commit_sha":null,"homepage":"https://www.agencykit.so/notion-cms/guide/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agency-kit.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-12T01:30:10.000Z","updated_at":"2025-01-29T06:04:46.000Z","dependencies_parsed_at":"2023-07-06T14:16:16.431Z","dependency_job_id":"bfbb1f68-d32d-4a11-8e88-64b35cef9e9b","html_url":"https://github.com/agency-kit/notion-cms","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agency-kit%2Fnotion-cms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agency-kit%2Fnotion-cms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agency-kit%2Fnotion-cms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agency-kit%2Fnotion-cms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agency-kit","download_url":"https://codeload.github.com/agency-kit/notion-cms/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248161712,"owners_count":21057639,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cms","content","headless","headless-cms","jamstack","notion","notion-api","notion-blog","ssg"],"created_at":"2024-09-24T22:41:05.581Z","updated_at":"2025-04-10T05:23:12.631Z","avatar_url":"https://github.com/agency-kit.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\n\u003cimg src=\"/public/subtle_gltch_logo.png\"\u003e\n\n\u003ch1 align=\"center\"\u003e\u003ci\u003eThe\u003c/i\u003e Notion CMS\u003c/h1\u003e \n\n\u003c/p\u003e\n\n\u003ch3 align=\"center\"\u003eLeverage the \u003cstrong\u003epower\u003c/strong\u003e of Notion for your website's content organization and creation,\u003c/h3\u003e\n\u003cp align=\"center\"\u003ewith the \u003cstrong\u003esimplicity\u003c/strong\u003e of Ghost's Content API.\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://img.shields.io/npm/v/@agency-kit/notion-cms\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/@agency-kit/notion-cms\" alt=\"NPM Version\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/agency-kit/notion-cms/actions/workflows/main.yml/badge.svg\"\u003e\n    \u003cimg src=\"https://github.com/agency-kit/notion-cms/actions/workflows/main.yml/badge.svg\" alt=\"workflow\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://img.shields.io/npm/dm/@agency-kit/notion-cms\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/dm/@agency-kit/notion-cms\" alt=\"NPM\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://img.shields.io/github/commit-activity/m/agency-kit/notion-cms\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/commit-activity/m/agency-kit/notion-cms\" alt=\"commit activity\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n![notion -_  notionCMS  -_ prod](https://github.com/agency-kit/notion-cms/assets/68669571/b5990c57-d3a9-49ce-ba67-02b67f3b545c)\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.agencykit.so/notion-cms/guide/\"\u003edocs\u003c/a\u003e |\n  \u003ca href=\"https://www.agencykit.so/notion-cms/quickstart/\"\u003equickstart\u003c/a\u003e\n\u003c/p\u003e\n\n## Features \n\n🏗️  Framework agnostic - it’s just JS.  \n🌲  Build a collection-based CMS tree from your Notion database.  \n🎚️  Leverage database structure to control your routing structure.  \n⚙️   Geared for Static Site Generation.  \n📑  Transform Notion blocks → Markdown, plaintext, and (customizable) html.  \n🗃️  Optimized Content Caching for super fast builds.  \n🧩  Plugin ready with some powerful core plugins on the way.  \n🦾  Tagging, filtering, path queries, and tree-walking utilities.  \n⌨️   Totally Typesafe.  \n\n## Install\n\n``` npm install @agency-kit/notion-cms ```   \n```pnpm add @agency-kit/notion-cms```  \n```yarn add @agency-kit/notion-cms```  \n\n## Why.\n\nNotion excels at managing content. It also has a great API and SDK. But why is it so challenging to _actually_ leverage Notion as a CMS (Content Management System) in production? \n\nUntil recently there wasn't support for sub-pages (sub-items in a database) in Notion. So most existing Notion-as-a-cms solutions don't provide a way to leverage this new feature, which turns out to be crucial for building a collection-based CMS. Another barrier is that pulling content from Notion can be time consuming. Responses can take a few seconds at times, the API provides a lot of data to sift through, and multiple calls to different endpoints are required in order to go from CMS database to the content for each page. All of this together results in a less than excellent developer experience when using a static site generator that often makes requests on each build.\n\nNotionCMS exists to address each of these issues and provide an excellent developer experience while using Notion as your Content Management System.\n\n## The Database Structure\n\nIn order to make use of NotionCMS, you have to subscribe to a specific database structure. 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.\n\nSee the structure in this template [this template](https://cooked-shovel-3c3.notion.site/NotionCMS-Quickstart-Database-Template-719f1f9d1547465d96bcd7e80333c831?pvs=4).\n\n## Basic Usage\n\n```javascript\n\n// initialize\nconst myCoolCMS = new NotionCMS({\n  databaseId: 'e4fcd5b3-1d6a-4afd-b951-10d56ce436ad',\n  notionAPIKey: process.env.NOTION,\n  // Other options\n})\n\n// Pull down all Notion content\nawait myCoolCMS.pull()\n\n// Access the routes here:\nconsole.log(myCoolCMS.routes)\n\n// Access the page content here:\nconsole.log(myCoolCMS.data)\n\n// Access paths like this:\nconst postA = myCoolCMS.data['/posts']['/how-to-build-a-blog-with-notion']\nconst postB = myCoolCMS.data['/posts']['/how-to-use-notion-cms']\n\n```\n\n## Advanced Usage\n\n```javascript\n\nconst customPlugin = () =\u003e {\n  return {\n    name: 'my-custom-plugin',\n    hook: 'pre-parse', // other option is 'post-parse'\n    // list of blocks to transform.\n    // If hook is post parse, its the string of html parsed from blocks\n    exec: (blocksOrHtml) =\u003e {\n      // do some transformations,\n      const transformedBlocksOrHtml = someXform(blocksOrHtml)\n      return transformedBlocksOrHtml\n    }\n  }\n}\n\nconst myAdvancedCMS = new NotionCMS({\n  databaseId: 'e4fcd5b3-1d6a-4afd-b951-10d56ce436ad',\n  notionAPIKey: process.env.NOTION,\n  rootUrl: 'https://mycoolsite.com',\n  localCacheDirectory: `${process.cwd()}/localcache/`,\n  refreshTimeout: '1 hour',\n  plugins: [customPlugin()],\n})\n\nawait myAdvancedCMS.pull()\n\n```\n\nSee the full [API reference](https://www.agencykit.so/notion-cms/guide/api/).\n\n## Some Helper methods\n\n```javascript\n// returns page reference\nmyCMS.queryByPath('/full/path/to/page')\n\n// returns an array of only child pages of a page looked up using the key.\n// This runs queryByPath under the hood so you can save a step\nmyCMS.filterSubPages('/full/path/to/page' /* or Page reference*/)\n\n// returns page object without any children - just the content. Useful for serializing and sending a\n// single pages data to the client.\nmyCoolCMS.rejectSubPages('/full/path/to/page' /* or Page reference*/)\n\n// Get tagged collections this way or by passing a single tag:\nconst tagged = myCoolCMS.getTaggedCollection(['blog', 'programming'])\n\n// walk the CMS from the root node and perform some operation for each node.\n// the node parameter will be of type PageContent so you have access to all of the page data\nmyCoolCMS.walk(node =\u003e console.log(node), '/partial/path/to/start')\n\n// for async callbacks\nawait myCoolCMS.asyncWalk(async node =\u003e await asynchronousFunc())\n```\n\n## Project Stats\n\n![Alt](https://repobeats.axiom.co/api/embed/c2535fbb6cbc2731c212c332d5bc6cd695c32e0a.svg \"Repobeats analytics image\")\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagency-kit%2Fnotion-cms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagency-kit%2Fnotion-cms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagency-kit%2Fnotion-cms/lists"}