Tech
React

A good tutorial for the next js where you will get to know about hoe the things is working behind the sences/
hellpnextreact

Author
Kunal Arya
Date
May 4, 2025
Description
A good tutorial for the next js where you will get to know about hoe the things is working behind the sences/
Featured
no
Published
Published
ReadTime
3 min
category
Tech
created at
May 4, 2025
slug
react
tag
hellp
next
react
Building a Next.js Blog with Notion as a Database
This guide walks you through creating a blog using Next.js as the frontend and Notion as your content database, with automatic updates when your Notion pages change.
Prerequisites
- Node.js installed (v16.8.0 or higher)
- A Notion account
- Basic knowledge of React and JavaScript
Step 1: Set up your Notion database
- Create a new Notion database for your blog posts:
- Create a new page in Notion
- Create a new database (full page or inline)
- Add the following properties to your database:
Title
(type: Title)Slug
(type: Text)Published
(type: Checkbox)Date
(type: Date)Tags
(type: Multi-select)Description
(type: Text)
- Set up Notion API access:
- Go to Notion Developers
- Create a new integration
- Copy your integration token (keep this secure)
- Share your database with your integration (click "Share" on your database and add your integration)
- Copy your database ID (from the URL, it's the part after the workspace name and before the question mark)
Step 2: Create your Next.js project
- Initialize a new Next.js project:
npx create-next-app@latest my-notion-blog cd my-notion-blog
- Install required dependencies:
npm install @notionhq/client notion-to-md react-markdown
Step 3: Configure environment variables
Create a
.env.local
file in your project root:NOTION_API_KEY=your_integration_token NOTION_DATABASE_ID=your_database_id REVALIDATE_SECRET=random_string_for_security
Step 4: Set up Notion client
Create a new file
lib/notion.js
:import { Client } from "@notionhq/client"; import { NotionToMarkdown } from "notion-to-md"; const notion = new Client({ auth: process.env.NOTION_API_KEY, }); const n2m = new NotionToMarkdown({ notionClient: notion }); export async function getAllPosts() { const databaseId = process.env.NOTION_DATABASE_ID; const response = await notion.databases.query({ database_id: databaseId, filter: { property: "Published", checkbox: { equals: true, }, }, sorts: [ { property: "Date", direction: "descending", }, ], }); return response.results.map((page) => { return { id: page.id, title: page.properties.Title.title[0]?.plain_text || "Untitled", slug: page.properties.Slug.rich_text[0]?.plain_text || "", date: page.properties.Date.date?.start || "", tags: page.properties.Tags.multi_select.map((tag) => tag.name), description: page.properties.Description.rich_text[0]?.plain_text || "", }; }); } export async function getPostBySlug(slug) { const databaseId = process.env.NOTION_DATABASE_ID; const response = await notion.databases.query({ database_id: databaseId, filter: { property: "Slug", rich_text: { equals: slug, }, }, }); if (response.results.length === 0) { return null; } const page = response.results[0]; const mdBlocks = await n2m.pageToMarkdown(page.id); const markdown = n2m.toMarkdownString(mdBlocks); return { id: page.id, title: page.properties.Title.title[0]?.plain_text || "Untitled", slug: page.properties.Slug.rich_text[0]?.plain_text || "", date: page.properties.Date.date?.start || "", tags: page.properties.Tags.multi_select.map((tag) => tag.name), description: page.properties.Description.rich_text[0]?.plain_text || "", content: markdown.parent, }; }
Step 5: Create pages and components
1. Home Page (app/page.js
)
import Link from "next/link"; import { getAllPosts } from "@/lib/notion"; export const revalidate = 60; // Revalidate this page every 60 seconds export default async function Home() { const posts = await getAllPosts(); return ( <main className="container mx-auto px-4 py-8"> <h1 className="text-3xl font-bold mb-8">My Blog</h1> <div className="grid gap-6"> {posts.map((post) => ( <article key={post.id} className="border p-4 rounded-lg"> <h2 className="text-xl font-bold"> <Link href={`/blog/${post.slug}`}>{post.title}</Link> </h2> <div className="text-gray-500 text-sm mt-1">{new Date(post.date).toLocaleDateString()}</div> {post.tags.length > 0 && ( <div className="flex gap-2 mt-2"> {post.tags.map((tag) => ( <span key={tag} className="bg-gray-100 text-xs px-2 py-1 rounded"> {tag} </span> ))} </div> )} <p className="mt-2">{post.description}</p> </article> ))} </div> </main> ); }
2. Blog Post Page (app/blog/[slug]/page.js
)
import { getPostBySlug, getAllPosts } from "@/lib/notion"; import ReactMarkdown from "react-markdown"; import Link from "next/link"; import { notFound } from "next/navigation"; export const revalidate = 60; // Revalidate this page every 60 seconds export async function generateStaticParams() { const posts = await getAllPosts(); return posts.map((post) => ({ slug: post.slug })); } export default async function BlogPost({ params }) { const post = await getPostBySlug(params.slug); if (!post) { notFound(); } return ( <main className="container mx-auto px-4 py-8"> <Link href="/" className="text-blue-500 mb-6 block">← Back to all posts</Link> <article> <h1 className="text-3xl font-bold mb-2">{post.title}</h1> <div className="text-gray-500 mb-4">{new Date(post.date).toLocaleDateString()}</div> {post.tags.length > 0 && ( <div className="flex gap-2 mb-6"> {post.tags.map((tag) => ( <span key={tag} className="bg-gray-100 text-xs px-2 py-1 rounded"> {tag} </span> ))} </div> )} <div className="prose max-w-none"> <ReactMarkdown>{post.content}</ReactMarkdown> </div> </article> </main> ); }
Step 6: Set up on-demand revalidation
Create a new file
app/api/revalidate/route.js
:import { revalidatePath } from "next/cache"; import { NextResponse } from "next/server"; export async function POST(request) { const requestData = await request.json(); const { path, secret } = requestData; // Check for secret to confirm this is a valid request if (secret !== process.env.REVALIDATE_SECRET) { return NextResponse.json({ message: "Invalid token" }, { status: 401 }); } try { // This will revalidate the specified path if (path) { revalidatePath(path); return NextResponse.json({ revalidated: true, path }); } // If no path is provided, revalidate the homepage and all blog posts revalidatePath("/"); revalidatePath("/blog"); return NextResponse.json({ revalidated: true, path: "all" }); } catch (err) { // If there was an error, Next.js will continue // to show the last successfully generated page return NextResponse.json({ message: "Error revalidating" }, { status: 500 }); } }
Step 7: Set up Notion webhook (optional)
For real-time updates when Notion content changes, you can use Notion's "page_updated" webhooks or a third-party service like Pipedream or n8n to trigger your revalidation endpoint.
If you're using Pipedream, create a workflow that:
- Triggers on Notion page updates (using their Notion integration)
- Sends a POST request to your revalidation endpoint: with the body:
<https://your-site.com/api/revalidate>
{ "secret": "your_revalidate_secret", "path": "/" }
Step 8: Deploy your application
You can deploy your Next.js application to platforms like Vercel or Netlify:
- Push your code to a GitHub repository
- Connect your repository to Vercel or Netlify
- Add your environment variables to the deployment platform
- Deploy your application
Conclusion
You now have a fully functional blog that uses Notion as a CMS and Next.js as the frontend. When you update content in Notion, your website will automatically refresh with the new content.
- For immediate updates: Use the webhook approach
- For scheduled updates: Rely on the revalidation timing you've set (60 seconds in our example)
Additional Improvements
- Add image support: Enhance the markdown renderer to handle Notion images
- Create tag filters: Add pages to filter posts by tags
- Add pagination: Implement pagination for the blog list
- Add search functionality: Create a search feature for your blog posts
- Custom styling: Improve the design with Tailwind CSS or another styling solution
About

Kunal Arya
Web Developer
A good tutorial for the next js where you will get to know about hoe the things is working behind the sences/
📌 India

MANAGEMENT
AI in Business Management: Improving Efficiency and Decision Making
Ethan Caldwell on July 7, 2024

TECHNOLOGY
The Future of Remote Work: Trends and Best Practices
Sarah Johnson on August 12, 2024

INNOVATION
Sustainable Business Models for the Modern Economy
Alex Rivera on September 3, 2024
Kunal Arya
Developer, builder, and problem-solver with a passion for clean code, product thinking, and scalable tech..
© 2024 Kunal Arya. All Rights Reserved.