Giscus Comments in Hugo: Lightweight GitHub Discussions Integration
Table of Contents
Introduction#
As part of my review of comment solutions for static blogs, I decided to test Giscus. It is an open-source tool that uses GitHub Discussions as its backend.
I was intrigued mainly by the promise of high performance and privacy. Below, I present an analysis of this solution, an implementation guide for Hugo, and the conclusions from my performance tests.
What exactly is Giscus?#
Giscus is a widget that connects your website directly to the GitHub API. When a reader leaves a comment under a post, the system automatically creates a new discussion (or adds a reply) in the connected GitHub repository.
From an architecture perspective, it is a solution that is brilliant in its simplicity:
- Zero database – GitHub manages everything.
- No tracking – there are no scripts tracking the user across the web.
- Markdown – comments support full GitHub-flavored markdown (code, tables, links).
Prerequisites#
Before we start the configuration, you need to know about one key architectural limitation. Giscus requires the repository storing discussions to be public. This is due to how the GitHub API works – the client-side script must be able to read the discussions.
What we need to start:
- A public repository on GitHub.
- The “Discussions” feature enabled in that repository.
- The Giscus app installed.
Configuration: Step by Step#
The integration process is relatively simple. I will walk you through my configuration path for Hugo.
1. Preparing the repository#
If your repository is private, you must change its visibility in the settings (Settings -> Danger Zone -> Change repository visibility).
2. Activating Discussions and installing the app#
In the repository settings (General tab -> Features section), check the Discussions option. A good practice is to create a separate category for comments, for example, “Comments” with the type Announcement.
Next, we install the Giscus bot from github.com/apps/giscus. During installation, I chose the option to grant access only to the specific blog repository, which is a safer approach.
3. Generating the configuration#
It is most convenient to use the configurator at giscus.app. Key settings worth paying attention to:
- Mapping: I chose
pathname. This guarantees that every post will have a unique discussion thread based on the URL path. - Category: Point to the previously created “Comments” category.
- Theme: I recommend
preferred_color_scheme. Thanks to this, the widget will automatically adapt to the light/dark mode of the user’s system.
4. Integration with Hugo#
After generating the script, instead of pasting it directly, I created a flexible partial. This allows for easy management of parameters from the configuration file level.
File: layouts/partials/comments/giscus.html
{{- if .Site.Params.giscus.repo -}}
<script src="https://giscus.app/client.js"
data-repo="{{ .Site.Params.giscus.repo }}"
data-repo-id="{{ .Site.Params.giscus.repoId }}"
data-category="{{ .Site.Params.giscus.category }}"
data-category-id="{{ .Site.Params.giscus.categoryId }}"
data-mapping="pathname"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="top"
data-theme="preferred_color_scheme"
data-lang="{{ .Language.Lang }}"
crossorigin="anonymous"
async>
</script>
{{- end -}}
Pay attention to the line data-lang="{{ .Language.Lang }}". This is a simple trick that automatically switches the Giscus interface language depending on the language version of your blog.
Next, we update the hugo.toml file:
[params]
commentSystem = "giscus"
# Giscus Configuration (at the end of the file)
[params.giscus]
repo = "your-username/your-repo"
repoId = "R_kgDO..." # ID generated by giscus.app
category = "Comments"
categoryId = "DIC_kwDO..."
5. Comment Dispatcher#
To keep the code clean and make it easy to switch systems in the future (e.g., for further testing), I use a simple “dispatcher”.
File: layouts/partials/comments.html
{{- $commentSystem := .Site.Params.commentSystem -}}
{{- if eq $commentSystem "giscus" -}}
{{ partial "comments/giscus.html" . }}
{{- else if eq $commentSystem "disqus" -}}
{{ partial "comments/disqus.html" . }}
{{- end -}}
Performance and “Overhead” Analysis#
I checked how Giscus affects page load time compared to a page without comments.
Baseline (no comments):
- Transfer: 311 KB
- Load time: 1.20s
With Giscus enabled:
- Transfer: 413 KB (+102 KB)
- Load time: 4.46s (First Contentful Paint remains unchanged, the script loads asynchronously)
Giscus is basically just one JS file (main.js, about 81 KB) and some CSS styles. The whole thing is around 116 KB.
Who is this solution for?#
After testing, I have a clear picture of the target group.
Giscus is a great choice if:
- Your audience consists of developers. The requirement to have a GitHub account is a natural filter. For a dev-blog, this is an advantage (higher discussion quality); for a cooking blog – it’s a dealbreaker.
- You care about a “green” Lighthouse score. Low performance overhead is key for static sites.
- You value Open Source. The code is open, free, and has no ads.
It is worth considering alternatives when:
- You run a corporate/enterprise site and cannot make the repository public.
- Your readers are not technical (the need to log in via GitHub will scare them off).
Summary#
Giscus passed my tests very successfully. It is a modern approach to comments that removes unnecessary additions (ads, tracking, heavy scripts), leaving only the essence of the discussion.
Integration with Hugo is seamless, and multilingual support works “out of the box”. If your audience lives in the GitHub ecosystem, this is currently one of the most interesting systems on the market.
I encourage you to test it yourself – configuration takes about 10 minutes, and if needed, returning to the previous solution is just changing one line in hugo.toml.