In this guide, we gonna implement a blog using Notion as a content management system.
The @kit/notion package contains a type-safe client built using zod to validate the data. Our client is built on top of the notionhq/client package which is the official Notion client.
Create a notion database
The easiest way is to import our database template.
Download the database template.
Blog Template
We recommend you to use our template to make it work with the already existing ui. But you can customize it to your needs.
Import it in your Notion workspace.
Importing the blog database template in Notion
Set your Notion Connection to expose your data
Add a new integration.
In the browser, go to https://www.notion.so/profile/integrations and add a "New integration".
No need to set type to Public, you can let Internal.
Configure your integration settings.
In "Configuration" tab > Capabilities we gonna need :
- Select "Read content" only (remove the other capabilities)
- Select "No user information" (in the "User capabilities" section)
Set the NOTION_INTEGRATION_SECRET environment variable.
Show the "Internal Integration Secret" field and copy the value.
Use the copied value to set the NOTION_INTEGRATION_SECRET environment variable.
NOTION_INTEGRATION_SECRET=your-integration-secretSet your config file
Create a config/cms.config.ts file in your application and set the NOTION_INTEGRATION_SECRET environment variable.
'server-only';
import { parseNotionConfig } from '@kit/notion/config';
import { envs } from '~/envs';
export const notionConfig = parseNotionConfig({
auth: envs().NOTION_INTEGRATION_SECRET,
contentTypes: {
// edit this object to fit your needs
// your content types here ...
},
});| Prop | Type | Default |
|---|---|---|
contentTypes* | Record<string, { id: string; def: AnyContentTypeDef; }> | |
auth* | string |
Add a new content type
Connect you database
Connect you database to your previously created integration
Connecting your database to your previously created integration
Get your database source id
Getting your database source id
Set the NOTION_POSTS_DB_ID environment variable.
NOTION_POSTS_DB_ID=your-database-source-idSet your notion definition in the config file
To let the @kit/notion package to know the nature of your database, you need to add it in the contentTypes object.
'server-only'; import { parseNotionConfig } from '@kit/notion/config'; import { envs } from '~/envs'; export const notionConfig = parseNotionConfig({ auth: envs().NOTION_INTEGRATION_SECRET, contentTypes: { posts: { id: envs().NOTION_POSTS_DB_ID, def: { categories: 'multi_select', language: 'select', description: 'rich_text', slug: 'rich_text', image: 'files', status: 'status', title: 'title', }, }, }, });
Use the following tool to get your notion definition.
Once your defintion is fetched, you can refresh your "Internal Integration Secret" if you want to have an easy mind.
What It Does
@kit/notion maps Notion database schemas to typed content models and provides client, UI, and API helpers.
When To Use
- Non-technical editors manage content in Notion.
- You need API-backed docs/blog content with typed mapping.
Prerequisites
- Notion integration secret.
- Database IDs and property definitions.
This page describes the standard kit integration path; adapt app-specific paths and config names when your project differs.
How To Use
Define Notion config.
import { parseNotionConfig } from '@kit/notion/config'; export const notionConfig = parseNotionConfig({ auth: process.env.NOTION_INTEGRATION_SECRET!, contentTypes: { posts: { id: process.env.NOTION_POSTS_DB_ID!, def: { title: 'title', slug: 'rich_text', description: 'rich_text', status: 'status', }, }, }, });
Use content client and helpers.
NotionContentClientfor content retrieval/markdown.- API handlers from
@kit/notion/apifor search/render/export endpoints.
MCP Context
capability: notion_content_backend
entrypoints:
- @kit/notion/config
- @kit/notion/client
- @kit/notion/api
inputs:
- integration_secret
- content_type_schema_mapping
outputs:
- typed_notion_content
constraints:
- each content type must satisfy required fields (slug/title or roadmap rules)
side_effects:
- Notion API read trafficAgent Recipe
- Create Notion integration and get secret.
- Map each content type schema in
parseNotionConfig. - Add API routes and page loaders using notion helpers.
Troubleshooting
- Validation errors usually indicate wrong property types in
defmapping. - Empty results often mean integration not connected to target database.
Related
Repository-native documentation and MDX rendering with @kit/fumadocs.
Expose content as markdown endpoints for AI tooling.
How is this guide?
Last updated on 3/23/2026