DEV Community

Cover image for Adding Giscus Comments to Next.js Blog Pages
Mario
Mario

Posted on • Originally published at mariocodes.space

Adding Giscus Comments to Next.js Blog Pages

Why Giscus?

Every blog needs a way to hear from readers. I wanted a comment system that was:

  • Free and open source — no vendor lock-in or monthly fees
  • GitHub-native — my readers are mostly developers already on GitHub
  • Zero database — discussions live in a GitHub repo, not a server I manage
  • Theme-aware — it had to match my site's light and dark mode

Giscus checks every box. It uses GitHub Discussions as the backend and renders a clean embed on your page. Each URL path gets its own discussion thread automatically.

Some other options were:

  • utterances: **The primary inspiration for giscus. It uses **GitHub Issues instead of Discussions to store comments. It is extremely lightweight but does not support threaded replies as natively as giscus.
  • Gitalk**: **A modern component also based on GitHub Issues. It features a "distraction-free" mode and support for multiple languages.
  • Vssue: Supports not just GitHub, but also GitLab, Bitbucket, Gitee, and Gitea.

andrewdoering.org +4

At the end Giscus seemed like the better option.

Prerequisites

Before starting, make sure you have:

  • A Next.js project (App Router)
  • A GitHub account
  • Node.js and npm/yarn/pnpm installed

Step 1: Create a Dedicated GitHub Repository

Giscus needs a GitHub repo where discussions will be stored. I recommend creating a separate repo (e.g., your-username/blog-comments) rather than
using your main portfolio repo. This keeps your commit history clean and lets you manage comment permissions independently.

Go to GitHub → New repository → name it blog-comments → set it to Public (Giscus requires public repos).

Step 2: Enable GitHub Discussions

In your new repo:

  1. Go to Settings → General
  2. Scroll to the Features section
  3. Check Discussions
  4. Click Save

Then navigate to the Discussions tab and create a new category called Blog Comments (type: Announcement works well — it prevents random discussion
creation).

Step 3: Configure Giscus and Get Your IDs

Visit giscus.app and fill in the configuration form:

  • Repository: your-username/blog-comments
  • Page ↔ Discussions Mapping: pathname (each URL gets its own thread)
  • Discussion Category: Blog Comments
  • Features: Enable reactions

After submitting, Giscus will generate a script tag. Copy the data-repo-id and data-category-id values — you'll need these as environment
variables.

Step 4: Install the Package

npm install @giscus/react

Step 5: Create the BlogComments Component

Create app/blog/components/blog-comments.tsx:

`  "use client";
  import Giscus from "@giscus/react";
  import { useTheme } from "../../components/theme-provider";
export default function BlogComments() {
    const { theme } = useTheme();
return (
      <section className="mt-16 pt-12 border-t border-[var(--color-primary)]/20">
        <h2 className="text-2xl font-bold text-[var(--color-text)] mb-8">
          Comments
        </h2>
        <Giscus
          repo="your-username/blog-comments"
          repoId={process.env.NEXT_PUBLIC_GISCUS_REPO_ID ?? ""}
          category="Blog Comments"
          categoryId={process.env.NEXT_PUBLIC_GISCUS_CATEGORY_ID ?? ""}
          mapping="pathname"
          reactionsEnabled="1"
          emitMetadata="0"
          inputPosition="top"
          theme={theme === "dark" ? "dark" : "light"}
          lang="en"
          loading="lazy"
        />
      </section>
    );
  }`
Enter fullscreen mode Exit fullscreen mode

The key detail here is theme={theme === "dark" ? "dark" : "light"}. By reading from useTheme() — the same context your toggle button uses Giscus instantly switches its own theme whenever the user flips the site theme. No extra event listeners, no flash of the wrong colors.

The component is marked "use client" because useTheme is a React hook and Giscus itself needs browser APIs. The rest of your blog page can stay a
server component.

Step 6: Add Environment Variables

Add to your .env.local:

NEXT_PUBLIC_GISCUS_REPO_ID=R_your_repo_id_here
NEXT_PUBLIC_GISCUS_CATEGORY_ID=DIC_your_category_id_here

These are prefixed with NEXT_PUBLIC_ so they're available in the client bundle. They're not secret — they're visible in the Giscus-generated script tag anyway — but keeping them in env vars avoids hardcoding and makes deployment config explicit.

For Vercel, add the same two variables in Project Settings → Environment Variables.

Step 7: Integrate into the Blog Post Page

In app/blog/[slug]/page.tsx, import and render BlogComments inside the narrow content container, after the post body:

import BlogComments from "../components/blog-comments";

// inside the JSX:
<div className="max-w-3xl mx-auto px-6 lg:px-8">
<BlogPostContent body={post.body} />
<BlogComments />
</div>

Placing it inside the same max-w-3xl container keeps comments aligned with the reading column — it feels like a natural continuation of the
article rather than a full-width widget bolted on at the bottom.

The Result

Readers who are logged into GitHub can comment directly on any post. Each article gets its own GitHub Discussion thread, created automatically on
the first comment. Reactions work out of the box. And when a visitor switches the site to dark mode, the comment widget instantly matches — no
lag, no mismatch.

The entire setup required zero backend work, zero database, and about 30 lines of code.

Wrapping Up

Giscus is one of the cleanest integrations I've added to this portfolio. If you're running a developer blog and your audience is on GitHub, it's hard to beat: free, open source, no cookies, no ads, and the comment data lives in a repo you own.

If you run into any issues setting this up — or just want to test that comments work — drop a message below.

Top comments (0)