rotion
v4.0.0
Published
This is react components that uses the notion API to display the notion's database and page.
Maintainers
Readme
Rotion is a set of components and tools that utilize the Notion API and React to build a website from your Notion databases and pages.
It is designed primarily for use with Next.js (or other React frameworks) and stores images and other files locally, so that you can build a fully static site or render the pages on a Node.js server.
https://rotion.linyo.ws
Features
- Fetch and convert Notion databases and pages into data for your site via the Notion API, at build time or on request.
- Local storage of images, PDFs, and other files.
- Rich React components (Gallery, Table, List, Page, and various Blocks).
- Works with static site generation and server rendering in frameworks such as Next.js (Server rendering).
- Next.js App Router support with
createClientLinkhelper (v2.0.1+). - Next.js Page Router support for traditional SSG workflows.
- TypeScript support.
Installation
npm install rotionUsage
1. Set Up Notion API
Create a Notion integration and obtain your API key and database ID:
- Go to Notion Integrations
- Create a new integration
- Copy the integration token
- Share your Notion pages/databases with the integration
- Copy the page/database IDs from their URLs
2. Export Data
Use the APIs under rotion to fetch data from Notion:
import { FetchDatabase, FetchBlocks, FetchPage } from 'rotion'
// Fetch a database
const db = await FetchDatabase({ database_id: 'YOUR_DATABASE_ID' })
// Fetch page blocks
const blocks = await FetchBlocks({ block_id: 'YOUR_PAGE_ID' })
// Fetch page information
const page = await FetchPage({ page_id: 'YOUR_PAGE_ID' })Incremental Cache
Fetched data is cached in .cache (change it with ROTION_CACHEDIR). By default, an existing cache is always reused. With ROTION_INCREMENTAL_CACHE=true, only changed data is fetched again: database queries are refreshed after ROTION_CACHE_AVAILABLE_DURATION milliseconds (default: 2 minutes), and pages and blocks are refreshed when the page's last_edited_time changes.
In this mode, pass the page's last_edited_time to FetchBlocks and FetchPage. Without it, an existing cache is always returned and edits are not reflected. Changes inside nested blocks such as toggles and columns update only the page's last_edited_time, so use the page's value, not a block's.
// Pages from a database already have last_edited_time
const db = await FetchDatabase({ database_id: 'YOUR_DATABASE_ID' })
for (const page of db.results) {
const blocks = await FetchBlocks({ block_id: page.id, last_edited_time: page.last_edited_time })
}
// Or fetch the latest page first ('force' always requests the API)
const page = await FetchPage({ page_id: 'YOUR_PAGE_ID', last_edited_time: 'force' })
const blocks = await FetchBlocks({ block_id: 'YOUR_PAGE_ID', last_edited_time: page.last_edited_time })3. Render with React Components
Next.js App Router (v15+)
For Next.js App Router, you need to set up the createClientLink helper:
Step 1: Create app/lib/rotion.ts:
'use client'
import { createClientLink } from 'rotion/ui'
import NextLink from 'next/link'
export const ClientLink = createClientLink(NextLink)Step 2: Use in your Server Components:
// app/page.tsx
import { Page } from 'rotion/ui'
import { FetchBlocks } from 'rotion'
import { ClientLink } from './lib/rotion'
import type { Link } from 'rotion/ui'
export default async function MyPage() {
const blocks = await FetchBlocks({ block_id: 'YOUR_PAGE_ID' })
return <Page blocks={blocks} link={ClientLink as Link} />
}Next.js Page Router
For Page Router, you can use Next.js Link directly:
// pages/index.tsx
import type { GetStaticProps } from 'next'
import { Page } from 'rotion/ui'
import { FetchBlocks } from 'rotion'
import NextLink from 'next/link'
export const getStaticProps: GetStaticProps = async () => {
const blocks = await FetchBlocks({ block_id: 'YOUR_PAGE_ID' })
return { props: { blocks } }
}
export default function MyPage({ blocks }) {
return <Page blocks={blocks} link={NextLink} />
}Database Views
Display Notion databases in different formats:
import { Gallery, Table, List, Calendar } from 'rotion/ui'
import { FetchDatabase } from 'rotion'
const db = await FetchDatabase({ database_id: 'YOUR_DATABASE_ID' })
// Gallery view
<Gallery db={db} keys={['Name', 'Description', 'Image']} />
// Table view
<Table db={db} keys={['Name', 'Status', 'Date']} />
// List view
<List db={db} keys={['Name', 'Tags']} />
// Calendar view
<Calendar db={db} date="Date" keys={['Name', 'Tags']} />Calendar options
Calendar view renders a monthly grid. Multi-day events (date properties with both start and end) are drawn as a single bar that spans the matching cells, with continuation across week boundaries.
<Calendar
db={db}
date="Date" // required: name of the date property
keys={['Name', 'Tags']} // properties to render inside each event bar
options={{
initialDate: '2026-04-01', // YYYY-MM-DD or YYYY-MM (default: today)
weekStart: 'monday', // 'sunday' | 'monday' (default: 'sunday')
locale: 'ja-JP', // overrides navigator.language for labels
href: { Name: '/blog/[id]' }, // same href/link/query API as other views
}}
/>Main Exports
Data Fetching Functions (from rotion)
FetchDatabase– Fetches and caches a Notion databaseFetchBlocks– Fetches and caches page blocksFetchPage– Fetches page informationFetchBreadcrumbs– Fetches breadcrumb information
UI Components (from rotion/ui)
Database Views:
Gallery– Gallery view for databasesTable– Table view for databasesList– List view for databasesCalendar– Monthly calendar view for databases (events placed on a date property)
Page & Blocks:
Page– Renders a complete Notion page- Various Block components (TextBlock, ImageBlock, CodeBlock, CalloutBlock, etc.)
Utilities:
Icon– Renders Notion iconsRichText– Renders Notion rich textCheckbox– Renders checkboxescreateClientLink– Helper for Next.js App Router (v2.0.1+)
Examples
The examples/ directory contains complete working examples demonstrating Notion database integration.
Database Setup
All examples require a Notion database with the following properties:
| Property Name | Property Type |
|--------------|---------------|
| Title | title |
| Tags | multi_select|
| Date | date |
nextjs-approuter
Next.js App Router example with database support:
- Database table view on the index page
- Dynamic
[id]routes for individual articles - Server Components with
generateStaticParams - CSS Modules for styling
cd examples/nextjs-approuter
cp .env.example .env.local
# Add your NOTION_TOKEN and NOTION_DATABASE_ID
npm install
npm run devnextjs-server
Next.js App Router example rendered on a Node.js server:
- Pages rendered on request and regenerated with
revalidate - Downloaded images and files served from
storage/by route handlers - Incremental cache, so edits in Notion appear without a rebuild
cd examples/nextjs-server
# Add your NOTION_TOKEN and NOTION_DATABASE_ID to .env.local
npm install
npm run build
npm startnextjs-pagerouter
Next.js Pages Router example with database support:
- Database table view using
getStaticProps - Dynamic
[id]routes withgetStaticPaths - Traditional SSG workflow
cd examples/nextjs-pagerouter
cp .env.example .env.local
# Add your NOTION_TOKEN and NOTION_DATABASE_ID
npm install
npm run devastro
Astro example with database support:
- Database table view in
.astrofiles - Dynamic routes with
getStaticPaths - React components with
client:load
cd examples/astro
cp .env.example .env
# Add your NOTION_TOKEN and NOTION_DATABASE_ID
npm install
npm run devEach example demonstrates:
- Database table view displaying all three properties
- Individual article pages with full content
- Navigation between database and article views
Scripts
npm run build– Build.npm run test– Run tests.npm run story– Launch Storybook.
Requirements
- Node.js 22.12 or later
- React 17, 18, or 19
- Next.js 13+ (for App Router features, Next.js 15+ recommended)
License
MIT
