Build a Static Page Media Site with the Notion API

Christian Nwamba

Building a static media site filled with gallery images from Notion is a way to present to users dynamically generated images from the stored data in Notion and serve the data to the client-side of a Next.js application.

What is Notion?

Notion is a note taking application that empowers users to be productive in their workflow.

What is Next.js?

Next.js is a React framework that gives you the flexibility of building scalable applications by allowing you render content on the server.

In this article, you will learn how to use the Notion application programming interface (API) to pre-render a static page with the data from Notion by querying the database. For each new data entered in Notion the client-side is updated.

The completed project demo is in a CodeSandbox. Fork and run the code to get started.

You can check out the live demo


The following are required to complete this tutorial:

  • Understanding of React and knowing Next.js is necessary
  • Node.js installed on your local machine. It is required for dependency installation using npm
  • Having an account on Notion. Sign up is free

Getting Started

To scaffold a new project with all the files and folders, run the command in your terminal:

1npx create-next-app notion-media-site

After the installation, navigate to the created project directory and run the command below to start the development server on port 3000. Open http://localhost:3000 in your browser to check this out.

1cd notion-media-site
3npm run dev

Next, let’s install the Notion SDK for JavaScript by running this command:

1npm install @notionhq/client

@notionhq/client: A simple and easy to use client for the Notion API

Creating the Notion Page

Before getting started with using the package, let’s create the page for the image gallery on Notion. Open a new browser tab and enter to begin.

Now, you’ll create a table with the following steps in your Notion dashboard.

  • Click the “+ New page” button
  • Give your page a name. The name here is not important as it can be called anything
  • Under the database options, select “Table”
  • Once it is opened, select the “New database” button
  • Rename the column tags and click it to change it “Edit property” type to “Files & media”
  • For the Name column, give each row a value for the corresponding image
  • For the img column, choose an image file on your local machine

If everything was done correctly, your “Table” database should look like this:

Creating an Integration

With the database created in Notion, it is time to create an integration that will enable the Next.js application have access to all the data from Notion by creating an integration.

The steps are outlined as follows:

  1. To develop a new integration, click the “Settings & members” button

  1. Next, click the links “Integrations” and “Develop your own integrations”

  1. Give your integration a name by clicking the “New integration” button

  1. Once everything has been done correctly with the selected workspace you want to install your integration and its capabilities, click “Submit” to create the integration
  2. Copy the “Internal Integration Token” which will be used later in development

  1. Let’s get the other environment variable, the Database ID which is 32 characters long from the URL of the page.
2 |--------- Database ID --------|
  1. The last thing to do here is to share the data from the created Notion page above with the new integration. Click the “Share” button and then invite the integration with the name of the integration and afterwards click the “Invite” button

PS: The whole setup is complete, now our app will be able to make requests for any data on the Notion page.

Creating the Image Gallery

Back in our project, let’s create an .env file for the secret token and database ID. Create the file in the root directory and copy the following code:

1// .env
4 NOTION_SECRET=<Internal Integration Token>

Next, in the index.js file under the pages folder, copy and paste the following code:

1// pages/index.js
3import React from "react";
4import { Client } from "@notionhq/client";
5import styles from "../styles/Home.module.css";
7const IndexPage = ({ items }) => {
8 return (
9 <div className={styles.container}>
10 <main className={styles.main}>
11 {React.Children.toArray(
12 => (
13 <div className={styles.card}>
14 <img
15 src={item.img}
16 alt="notion props img"
17 className={styles.img}
18 />
19 <p className={styles.title}>{item.title}</p>
20 </div>
21 ))
22 )}
23 </main>
24 </div>
25 );
28export const getStaticProps = async () => {
29 const notion = new Client({
30 auth: process.env.NOTION_SECRET
31 });
33 const data = await notion.databases.query({
34 database_id: process.env.NOTION_DATABASE_ID
35 });
36 const images = [];
37 data.results.forEach((result) => {
38 images.push({
39 img:[0].file.url,
40 title:[0].text.content
41 });
42 });
43 return {
44 props: {
45 items: images
46 }
47 };
50export default IndexPage;

In the code snippet above, the following takes place:

  • The use of the getStaticProps function which allows the pre-rendering of the page at build time using the props returned
  • A new Notion client created with the auth object passed set to process.env.NOTION_SECRET
  • Pass the next configuration object using process.env.NOTION_DATABASE_ID and query the items that exist on our page using notion.databases.query
  • With an empty array of images, pass the data.results array from the data variable and iterate over each item for the img, and title in the collection
  • Thereafter, push the new img and title into the images array. The results from this is the passed in props items that takes the img and title and render the data on the client-side

For the styling of the page, create a folder called styles in the root directory. In there, create two files, a globals.css and Home.module.css

Copy and paste the following code from these gist below into the respective files.




This article discussed the use of the Notion API in creating a static page and how it can be used as a content management tool (CMS) for your frontend applications.

Learn More

Christian Nwamba

Developer Advocate at AWS

A software engineer and developer advocate. I love to research and talk about web technologies and how to delight customers with them.