# react-notion-x: rendering Notion pages as React, and what it costs you

> react-notion-x turns a Notion page into a recordMap and renders it as React components, with heavyweight blocks opt-in. It is a good fit for Next.js sites that live off a Notion workspace, and a poor fit for anyone who needs the official Notion API.

**NotionX/react-notion-x** — Fast and accurate React renderer for Notion. TS batteries included. ⚡️

- Repository: https://github.com/NotionX/react-notion-x
- Website: https://react-notion-x-demo.transitivebullsh.it
- Stars: 5,432 · Forks: 648
- Language: TypeScript
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/notionx-react-notion-x

## The problem react-notion-x solves, and who it is actually for

Notion is a document tool, not a CMS. If you want a public site whose pages are edited in Notion, you need something that reads a Notion page and produces HTML. react-notion-x is that something on the React side: it takes a recordMap and renders it as React components. The README describes it as a "Fast and accurate React renderer for Notion" with TypeScript included, and the package is published under the MIT license.

The audience is narrower than the description suggests. The README's own Advice section points people who want "more control over your website via React" at the accompanying Next.js starter kit, which uses react-notion-x underneath, and tells readers that if they want even more control they are in the right place. So the intended user is someone who has already decided the starter kit is not enough: they want to own the page component, the routing and the bundle, and they are comfortable wiring those together themselves. A team that just wants a Notion-backed blog should start with the starter kit instead.

The framework-agnostic claim in the feature list is real but partial. The renderer is a React component, so it runs wherever React runs, including Vite and Remix. The examples shipped in the repository, however, are Next.js: there is a minimal example under examples/minimal and a fuller one under examples/full. The lazy-loading guidance in the README is written around next/dynamic. Nothing stops you from using another bundler, but you will be translating the examples rather than following them.

## How the recordMap pipeline works

There are two packages in play. notion-client fetches a page and returns a recordMap; react-notion-x renders that recordMap. The README's first example constructs a NotionAPI instance and calls getPage with a page id. The second passes the resulting recordMap into NotionRenderer with fullPage and darkMode props. That two-step split is the whole architecture: fetching and rendering are separate, so you can cache, transform or persist the recordMap without touching the renderer.

The renderer's default export is deliberately thin. The README states that heavier blocks are not included in the default NotionRenderer export because they are "too heavyweight for many use cases", and that you opt into them through NotionRenderer.components. Those components live under react-notion-x/third-party/*: Code, Collection, Equation, Modal and Pdf. If your content has a database view or an embedded PDF and you do not register the matching component, that block will not render the way you expect.

The README also recommends lazy-loading the optional components, and gives a next/dynamic example for each one. The reasoning is stated plainly: if your Notion content does not use one of those heavyweight components, it never gets loaded, which keeps the initial bundle small. Note that Pdf and Modal are shown with ssr: false in that example, while Code, Collection and Equation are not. That asymmetry is worth copying rather than flattening.

Styling is a separate import. The README marks react-notion-x/styles.css as required and shared by all of react-notion-x, then lists prismjs/themes/prism-tomorrow.css for code highlighting and katex/dist/katex.min.css for equations as optional. In a Next.js app it suggests placing those imports at the top of pages/_app.js. The Code component uses Prism under the hood and ships with JavaScript, TypeScript and CSS syntaxes by default; adding more languages means lazily loading Prism components at runtime, following the pattern in examples/full/components/NotionPage.tsx.

## Installing react-notion-x and rendering a first page

The repository is a pnpm workspace with packages and examples directories, and the root package.json sets engines.node to ">=20" and packageManager to pnpm@11.22.0. For consuming the library in your own app, the README's usage section is the starting point rather than the monorepo scripts, which are build tooling for the project itself.

The first step is fetching content. The README shows this with notion-client, and the page id in the example is the one used throughout the docs:

```ts
import { NotionAPI } from 'notion-client'

const notion = new NotionAPI()

const recordMap = await notion.getPage('067dd719a912471ea9a3ac10710e7fdf')
```

After that call you should have a recordMap object. That object is the only input the renderer needs. Rendering it is a single component with props:

```tsx
import React from 'react'
import { NotionRenderer } from 'react-notion-x'

export default ({ recordMap }) => (
  <NotionRenderer recordMap={recordMap} fullPage={true} darkMode={false} />
)
```

The fullPage and darkMode props are both shown explicitly in the README example, so pass them rather than relying on defaults. Without the stylesheet the markup will be present but unstyled, so import the required CSS in your app entry point:

```ts
// core styles shared by all of react-notion-x (required)
import 'react-notion-x/styles.css'

// used for code syntax highlighting (optional)
import 'prismjs/themes/prism-tomorrow.css'

// used for rendering equations (optional)
import 'katex/dist/katex.min.css'
```

If your page contains a code block, a database view, an equation, a PDF or a modal, register the matching component through the components prop. The README's example passes all five at once, which is the easiest way to see whether the block set you care about is covered:

```tsx
export default ({ recordMap }) => (
  <NotionRenderer
    recordMap={recordMap}
    components={{
      Code,
      Collection,
      Equation,
      Modal,
      Pdf
    }}
  />
)
```

For private pages, the README says to pass authToken and activeUser, retrieved from the browser under Development Tools > Application > Cookie as token_v2 and notion_user_id respectively, and recommends storing them as environment variables:

```tsx
const notion = new NotionAPI({
  activeUser: process.env.NOTION_ACTIVE_USER,
  authToken: process.env.NOTION_TOKEN_V2
})
```

Read that section carefully before relying on it. The README states that this is not the same as the API token provided by the official Notion API, because notion-client uses the unofficial Notion API that Notion's own apps use. You are authenticating with a browser session cookie, which is a different kind of dependency from a token issued to your integration.

## Where react-notion-x is the wrong tool

The unofficial API is the limitation that matters most, and the README is direct about it. A session cookie copied out of your browser is not a stable contract. It is tied to a logged-in account, it can expire, and it can be revoked by the platform at any time. If you build a site on private pages, the failure mode is not a bad render; it is the fetch failing and your pages having nothing to show. The README does not document any rollback or fallback behaviour for that case, so plan for it yourself.

The second constraint is block coverage. The supported block list exists in the README, and the optional component list is explicit about which heavyweight blocks are excluded from the default export. The practical consequence is that a page which looks fine in Notion can render incompletely in your app until you register the right third-party component and its CSS. That is a per-block decision, not a global switch.

The third is the framework fit. The library is framework agnostic in the sense that it is React, but the guidance, the examples and the lazy-loading pattern are all Next.js. If you are on a different React framework, you are on your own for the dynamic import equivalent and for server-side rendering decisions like the ssr: false shown for Pdf and Modal.

Finally, if you need the official Notion API, this is the wrong package. The README says so in the private pages section. The official API and the unofficial one are different surfaces, and react-notion-x is built on the second.

## How react-notion-x differs from a Notion-to-HTML renderer

The closest category of alternative is a renderer that converts Notion content to HTML at build or request time and hands you a string. react-notion-x does not do that. It keeps the Notion data structure intact as a recordMap and renders it with React components, which is why the components prop exists at all: you can swap in your own component for a given block type instead of post-processing generated markup.

The trade-off is that you inherit React's rendering model. You need a React tree, you need to think about which components load on the client, and you need the required stylesheet. A static HTML pipeline has none of those concerns and is easier to serve from a CDN as plain files. What it gives up is the ability to pass interactive components into block rendering, and the ability to reuse the same recordMap for a client-side render.

Within the React space, the README points at its own alternative first: the Next.js starter kit, which uses react-notion-x under the hood and is described as free. That is not a competitor so much as a layer above it. If the starter kit covers your case, using it means you are not maintaining the page component, the block registration or the lazy-loading setup yourself. Choosing react-notion-x directly is a decision to take that maintenance on in exchange for control.

## Maintenance, releases and what the MIT license means here

The repository is not archived, and the last push was on 2026-09-19. Recent releases include v8.0.8 on 2026-09-03, v8.0.7 on 2026-09-03 and v8.0.6 on 2026-08-23, and the root package.json carries version 8.0.8. The release script is "bumpp -r && pnpm publish -r", so packages are versioned and published together across the workspace.

That workspace shape affects your upgrade path. The root package.json is private and named "notion"; the published artifacts are the packages under packages/, including react-notion-x and notion-client. Because releases are coordinated, a minor bump can move both the fetcher and the renderer at once. Pin both packages together and read the release notes for the pair rather than upgrading one side.

The build and test tooling is part of the repo rather than your concern, but it tells you what the maintainers check: turbo runs build, test and typecheck across packages, oxfmt handles formatting, oxlint handles linting, and vitest runs unit tests. A pretest script runs the build first. The README also links a test suite covering "most of Notion's functionality". That suite is the closest thing to a compatibility statement you will get, since the underlying API is unofficial.

On licensing: the repository license is MIT, and the root package.json declares "license": "MIT". MIT permits commercial use and modification, but it also means the maintainers give no warranty. That matters more than usual here, because the unofficial API dependency is exactly the kind of thing a warranty would cover. This is a description of the license text, not legal advice; check the license file and your own obligations before shipping.

## Conclusion

Adopt react-notion-x if your content already lives in Notion and you want a Next.js site that renders it as React components, accepting that the data comes from the unofficial Notion API. Do not adopt it if you need the official Notion API, a non-React stack, or a guarantee that private-page cookies will keep working. Before committing, verify that your workspace's blocks are covered by the supported set, confirm your Node version satisfies the engines field, and decide up front whether you are willing to maintain the authToken and activeUser cookies yourself.

## FAQ

### How do I install and use react-notion-x in a React app?

Fetch a page with notion-client's NotionAPI and getPage to produce a recordMap, then pass that recordMap to NotionRenderer. Import react-notion-x/styles.css in your app entry point, and register any third-party components you need through the components prop.

### Does react-notion-x work with the official Notion API?

No. The README states that notion-client uses the unofficial Notion API, which is what all Notion apps use, and that the authToken and activeUser values for private pages are not the same as the token provided by the official Notion API.

### Why are some Notion blocks missing when I render a page with react-notion-x?

Heavier blocks such as Code, Collection, Equation, Modal and Pdf are not included in the default NotionRenderer export. The README says to import them from react-notion-x/third-party/* and pass them to the components prop, and to lazy-load them where possible.

### What Node version does react-notion-x require?

The root package.json sets engines.node to ">=20" and packageManager to pnpm@11.22.0. The repository is a pnpm workspace with packages and examples directories.

### How do I access private Notion pages with react-notion-x?

The README says to pass authToken and activeUser to the NotionAPI constructor, copying token_v2 and notion_user_id from your browser cookies, and recommends storing them as environment variables. It notes these are not the same as an official Notion API token.

## Sources

- [License: MIT](https://github.com/NotionX/react-notion-x/blob/master/LICENSE)
- [NotionX/react-notion-x on GitHub](https://github.com/NotionX/react-notion-x)
- [Project website](https://react-notion-x-demo.transitivebullsh.it)
- [README](https://github.com/NotionX/react-notion-x/blob/master/README.md)
- [Releases](https://github.com/NotionX/react-notion-x/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/notionx-react-notion-x
