DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for How to create a SEO-friendly website using NextJS & Notion API ?
Yacine Messaadi
Yacine Messaadi

Posted on • Updated on • Originally published at yacine-messaadi.com

How to create a SEO-friendly website using NextJS & Notion API ?

Today, we will see how to create your own SEO-friendly static website which can be a blog, an ecommerce, a portfolio or whatever you want it to become !

Live example here : my personal portfolio.
All the content is fetched from Notion by NextJS.

Source code here : Github Repo (OpenSource).
You can fork it, copy and do anything you want with this code, it's free !

Setting up the project

Create a Notion integration

Follow this link: https://www.notion.so/my-integrations and create a new internal integration.

  • Give it a name
  • Select the right workspace to link
  • Give it the ability to read your content

Then save it.

Build your Notion database

Create a page in your Notion workspace, containing a Database.
You can put the properties you want and the lines you want, but never let an empty line !
For example, there is the database used in this article (you can duplicate it):

Notion DB template

In a future step, you will need your database ID. To find it, click the Share button on your own database and get the ID between the / and the ?
The ID of the example database is f394d3f878ce4c6b88412da5391e4603 (don’t use this one).

Create a NextJS project

Make sure you have Node installed on your computer.
Execute this command line by replacing the example name by your own project name:

npx create-next-app notionapi-example
Enter fullscreen mode Exit fullscreen mode

Once the project created, open it in your preferred IDE (VS Code for me).

Build the website

Add NextJS Image optimization

In the next.config.js file, write this:

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  images: {
    domains: ["s3.us-west-2.amazonaws.com"],
  },
};

module.exports = nextConfig;
Enter fullscreen mode Exit fullscreen mode

Add TailwindCSS

Execute this command lines:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Enter fullscreen mode Exit fullscreen mode

It will create a tailwind.config.js file. Modify it to get the same as below:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};
Enter fullscreen mode Exit fullscreen mode

Copy these lines to the styles/globals.css file:

@tailwind base;
@tailwind components;
@tailwind utilities;

html,
body {
  scroll-behavior: smooth;
}
Enter fullscreen mode Exit fullscreen mode

Add the dependencies

Install the dependencies by running this:

npm install dotenv @notionhq/client@1.0.4
Enter fullscreen mode Exit fullscreen mode

Add your integration informations

Create a .env file at the root of your project.
Get your secret key on your integration dashboard.
Add your integration’s key and ID like this:

NOTION_API_KEY = YOUR INTEGRATION SECRET KEY
NOTION_DB_ID = YOUR DATABASE ID
Enter fullscreen mode Exit fullscreen mode

Creating the API call

Notion API doesn’t allow to call it from the front-end, so we must call it from our back-end, the pages/api folder.

Create a file named articles.js in this folder and write the code to instantiate the Notion API client and parse the content of our Notion page.

require("dotenv").config();
// the following lines are required to initialize a Notion client
const { Client } = require("@notionhq/client");
const notion = new Client({ auth: process.env.NOTION_API_KEY });
const databaseId = process.env.NOTION_DB_ID;

export default async function getArticles() {
  const response = await notion.databases.query({
    database_id: databaseId,
  });

  // options for the Date format of the articles
  const options = {
    year: "numeric",
    month: "long",
    day: "numeric",
  };

  const responseResults = response.results.map((page) => {
    return {
      id: page.id,
      tag: page.properties.tag.select.name,
      title: page.properties.title.title[0]?.plain_text,
      description: page.properties.description.rich_text[0].plain_text,
      image: page.properties.image.files[0].file.url,
      date: new Date(
        page.properties.creation_date.created_time
      ).toLocaleDateString("en-US", options),
    };
  });
  return responseResults;
}
Enter fullscreen mode Exit fullscreen mode

Clear the default page

Delete all the index.js page content, and replace it by those lines :

import Head from "next/head";
import Image from "next/image";
import getArticles from "./api/articles";

export default function Home({ articles }) {
  function buildArticleCards() {
    return articles.map((article) => {
      return (
        <a href="#" key={article.id} className="group rounded-xl pb-5">
          <div className="block overflow-hidden aspect-w-16 aspect-h-9 rounded-xl transition-all duration-200 backdrop-blur-xl backdrop-filter">
            <figure className="px-10 pt-10 mt-4 relative h-44">
              <Image
                layout="fill"
                src={article.image}
                alt={article.title}
                objectFit="contain"
                className="rounded-xl"
              />
            </figure>
          </div>
          <div className="flex items-center mt-6 space-x-2 ml-2">
            <p className="text-sm font-medium text-gray-900">{article.tag}</p>
            <span className="text-sm font-medium text-gray-900">β€’</span>
            <p className="text-sm font-medium text-gray-900">{article.date}</p>
          </div>
          <p className="mt-4 ml-2 text-xl font-bold text-gray-900 group-hover:text-gray-600">
            {article.title}
          </p>
        </a>
      );
    });
  }

  return (
    <div>
      <Head>
        <title>NextJSxNotion</title>
        <meta name="description" content="Created by Yacine Messaadi" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main>
        <h1 className="text-4xl my-10 text-center">Welcome to NextJSxNotion</h1>
        <section id="blogInsight">
          <h2 className="text-center mt-4 font-heading font-sans text-3xl sm:text-3xl">
            <span className="text-center self-center">Blog Articles</span>
          </h2>
          <div className="px-4 mx-auto sm:px-6 lg:px-8 max-w-7xl">
            <div className="grid grid-cols-1 gap-10 mt-6 xl:gap-20 sm:grid-cols-2 lg:grid-cols-3 sm:mt-10">
              {buildArticleCards()}
            </div>
          </div>
        </section>
      </main>
    </div>
  );
}

export async function getStaticProps() {
  const articles = await getArticles();
  return {
    props: {
      articles,
    },
    // Revalidate is a way to rebuild the static website following an interval of seconds.
    revalidate: 86400,
  };
}
Enter fullscreen mode Exit fullscreen mode

Try it out !

Start your server by writing the command below and open your browser to localhost:3000.

npm run dev
Enter fullscreen mode Exit fullscreen mode

The end

You are now able to start an amazing journey through the Notion API capabilities, mixed with the power of NextJS !

Top comments (2)

Collapse
gamerseo profile image
Gamerseo

Great post

Collapse
yacinemessaadi profile image
Yacine Messaadi Author

Thanks ! What would you like to read in the next article ?

🌚 Browsing with dark mode makes you a better developer by a factor of exactly 40.

It's a scientific fact.