Will
Liu

How to build a Notion-powered Next.js App in 5 minutes with notion-on-next

A quick guide to using notion-on-next

Last updated: Mon Jan 02 2023

#Notion
cover image

Notion-on-next Github

Why?

Next is a framework that is amazing for building static sites like portfolios and blogs. Notion is such a really powerful editor that can double as a CMS. Putting the two together means you get a site that is super fast, seo friendly, and easy to manage. At the time of writing (12/24/2022), you can do all of this on free plans from Notion and Vercel.

Tutorial

Setup

  1. Create a fresh Next app with npx create-next-app@latest --experimental-app
  1. cd your-app-name
  1. Install notion-on next: npm i notion-on-next
  1. Create a Notion integration and share your database with your newly created integration.
  1. Get your internal integration token, and add it to a .env file in the root directory as NOTION_KEY=yourtoken
  1. Run npx non setup . You can either add your personal databases, or if you’d like to start from a template go ahead and copy this page which contains two sample databases. Make sure to hit yes when prompted to download media and scaffold the app directory. Typescript is recommended.
  1. You’re ready to go! Run npm run dev and then visit http://localhost:3000/yourdatabasename to see your content.
  1. You might notice that your app is slow in development mode. This is because it needs to refetch your data from Notion whenever you refresh or go to a new page. To try out the production build, run npm run build and then npm run start.

Customizing

πŸ‘‹πŸ»
If you’re reading this on willliu.com, then the page you are on was built using this exact process!

After following instructions above, your site should look something like the screenshot below. If you aren’t seeing images, you can add cover images and then run npx non media. Notion-on-next gives you a super simple and minimally styled starting point. Customization is up to you!

Notion page image

Let’s say our database also has the properties Description (text) and Tags (multi-select). We want to display those in <Card>. To add the description, we can access it like this:

<div style={{ margin: "16px 0px 16px 0px" }}>
	  {page.properties.Description.rich_text[0].plain_text}
</div>

You might be thinking, how am I supposed to know that I have to access rich_text[0].plain_text? If you are using typescript, you can hover to see what properties you have available to access. If you are ever unsure, just console.log the object and you should be able to find your way.

Notion page image

And then we can add this snippet in for the tags.

<div>
    {page.properties.Tags.multi_select.map((tag, index) => {
      return (
        <span
          style={{
            backgroundColor: tag.color,
            color: `white`,
            margin: "4px",
            padding: "2px 4px 2px 4px",
            borderRadius: "4px",
            filter: "brightness(0.5)",
          }}
          key={tag.name + index}
        >
          {tag.name}
        </span>
      );
    })}
</div>

Boom! We’ve got descriptions and tags.

Notion page image

Tips and Tricks

Using the types

Your app directory will be scaffolded with components that reference types that match what you have in your database. In the example below, you can see that a component called DogsCard was generated from my database titled Dogs. Notion-on-next automatically generated a type DogsPageObjectResponse, which you can see matches the database.

Notion page image
Notion page image

Understanding the structure

Notion-on-next recommends using following structure.

β€”β€” /app

β€”β€”β€”β€” /databaseName

β€”β€”β€”β€”β€”β€”β€”β€”β€” page.tsx

β€”β€”β€”β€”β€”β€”β€”β€”β€” Card.tsx

β€”β€”β€”β€”β€”β€”β€”β€”β€” /[slug]

β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€” /page.tsx

  • /databaseName/page.tsx - Displays a list of your pages using the <Card> component
  • /databaseName/card.tsx - Displays a card that links to a page.
  • [slug]/page.tsx - Renders the page content and also runs generateStaticParams, which tells Next to build all of the pages as static pages.

Notion API page vs blocks.

Pages can be blocks, but blocks are not pages! A β€œpage” contains data such as the id, title, properties, and cover image. A β€œblock” contains content. Essentially, a page is the top section of the Notion page UI, and all of the content are child blocks.


Note: This post was written for notion-on-next version 1.0.16