Examples
The repository has three example projects in examples/ . All three build the same site from one Notion database: an index page with the database as a table, and one page per row with its content. They differ in the framework.
| Example | Framework | Fetches data in |
|---|---|---|
| nextjs-approuter | Next.js App Router | Server components, generateStaticParams, generateMetadata |
| nextjs-pagerouter | Next.js Pages Router | getStaticProps, getStaticPaths |
| astro | Astro with @astrojs/react | The frontmatter of .astro pages, getStaticPaths |
Prepare a database
Create a Notion database with these properties, add a few rows with some content, and connect your integration to it (see Getting started):
| Property | Type |
|---|---|
Title | Title |
Tags | Multi-select |
Date | Date |
The names must match: the examples pass ['Title', 'Tags', 'Date'] as keys and link the Title column to /[id].
Run an example
Each example needs two variables: NOTION_TOKEN, read by Rotion, and NOTION_DATABASE_ID, read by the example’s code. The Next.js examples load them from .env.local:
cd examples/nextjs-approuter
cat > .env.local <<'EOF'
NOTION_TOKEN=ntn_xxxxxxxxxxxxxxxxxxxxxxxx
NOTION_DATABASE_ID=668d797c76fa49349b05ad288df2d136
EOF
npm install
npm run devnpm run build writes a static export into out/. The examples install rotion from npm, not from the repository; their READMEs describe how to try a local build with npm pack.
nextjs-approuter
app/compornents/ClientLink.tsxwrapsnext/linkwithcreateClientLink.app/page.tsxfetches the database in a server component and renders it through a small client component around<Table>, withhref: { Title: '/[id]' }and the client link.app/compornents/Header.tsxis an async server component that fetches the same database again for its title; the second call is served from the cache.app/[id]/page.tsxlists the rows ingenerateStaticParams, fetches each page withFetchPage({ page_id, last_edited_time: 'force' })and its blocks with the page’slast_edited_time, reads the title frompage.meta, and showspage.icon?.srcwithnext/image.app/layout.tsximportsrotion/style-without-dark.css.next.config.tssetsoutput: 'export'andimages.unoptimized.
The walkthrough is in App Router.
nextjs-pagerouter
pages/index.tsxfetches the database ingetStaticPropsand renders<Table>withnext/linkpassed directly aslink.pages/[id].tsxreturns every row fromgetStaticPathswithfallback: false, and ingetStaticPropsfetches the page and the database in parallel, then the blocks.pages/_app.tsximportsrotion/style.css, so this example follows the system’s dark mode.
The walkthrough is in Pages Router.
astro
src/pages/index.astrofetches the database in its frontmatter and renders a React<Table>wrapper.src/pages/[id].astroreturns every row fromgetStaticPaths, and fetches each page and its blocks.src/components/NotionPage.tsxwraps<Page>. The pages hydrate the React components withclient:load.astro.config.mjsadds the React integration and setsoutput: 'static'.
The Astro example reads its variables from .env through import.meta.env:
cd examples/astro
cat > .env <<'EOF'
NOTION_TOKEN=ntn_xxxxxxxxxxxxxxxxxxxxxxxx
NOTION_DATABASE_ID=668d797c76fa49349b05ad288df2d136
EOF
npm install
npm run devRotion itself reads NOTION_TOKEN from process.env when it is imported, and the pages copy the value there from import.meta.env. Exporting the variable in the shell that runs the build (NOTION_TOKEN=... npm run build) sets it for Rotion regardless of how Astro loads .env. The development server runs at http://localhost:4321, and npm run build writes the site into dist/.