Giscus and GitHub Discussions: Comments Without Running a Comment Backend
Why I chose Giscus and GitHub Discussions for blog comments, how immutable post IDs keep bilingual threads together, and how the production cache fallback works.
My blog needed a place where readers could ask questions about a post and continue the conversation. The constraint was operational: I did not want to run a second user system, store comment data, or become responsible for a moderation backend. That led me to Giscus, which embeds a GitHub Discussion under each article. The website renders the conversation; GitHub stores it and handles identity.
The first version covers published Technical and Trading posts. It is deliberately a comment area, not a general forum. Readers who want to participate need a GitHub account, and the conversation remains available in its GitHub repository.
Choosing the ownership boundary
A custom comment service would give me complete control over accounts and interface, but it would also need authentication, persistence, abuse handling, backups, and ongoing security work. A hosted comment provider would remove much of that engineering while introducing a separate service, its pricing and data model. Since most early readers of these technical posts already use GitHub, Discussions offered a workable trade: fewer moving parts on my side, at the cost of excluding people unwilling to sign in with GitHub.
Here is my September 2026 qualitative comparison, not a measured score. The horizontal axis is ongoing work for the site owner; the vertical axis is the effort a reader must make before commenting. Hyvor Talk and Remark42 are shown with guest comments enabled. Subscription fees and data-portability terms are separate considerations, so the chart does not rank total cost.
The picture makes the trade visible: Giscus keeps my operating work low by making a GitHub account the entry ticket. Hyvor Talk supports guest comments but adds a hosted vendor and subscription; Remark42 supports anonymous access but I would operate its server and storage myself. Those positions are my assessment for this blog, not product ratings.
The comment data lives in the public chankay-discussions repository, separate from the site's source repository. The Giscus GitHub App is installed only on that repository, Discussions is enabled, and new article conversations go into an Announcements category. GitHub's discussion controls provide moderation. There is no comment table or visitor login in Payload CMS. This reduces infrastructure maintenance, but it does not remove the human work of reading and moderating replies.
The repository's giscus.json limits embedding to the production site origins and sets the default order to oldest first. Giscus documents this origin restriction as an exact comparison with the embedding page's origin. A preview domain therefore needs an explicit allowlist change before the widget can work there.
Give each post an identity that survives a rename
Giscus can find a discussion by URL, path, or title. All three can change here: posts have English and Chinese URLs, a slug can be edited, and the displayed title is localized. Mapping by any of those values could split one article into multiple conversations or lose the old thread after a rename.
Instead, the website uses Giscus's specific mapping with post:<Payload document ID> as the term. It enables strict matching, so similar titles are less likely to resolve to the wrong discussion. The two language versions use the same Payload ID and therefore reach the same thread; the widget language and surrounding copy still follow the page locale. Preserving document IDs during a future CMS migration now matters as much as preserving slugs.
The thread is resolved only when the reader approaches the comment area. This is the request sequence for an article that has comments enabled:
Giscus searches for a matching discussion when the embed loads; it creates one only when somebody first comments or reacts. Until then, the stable post:<ID> is a lookup key, not an empty discussion. The page also links to the repository's Discussions if the embed fails to load.
Keep the website in charge of presentation
Payload owns two editorial controls: a global Giscus configuration and commentsEnabled on each post. Older posts without the checkbox are treated as enabled. The server renders the section only for a published post with enabled, valid configuration. Switching a post off hides its embed; it does not delete an existing GitHub discussion.
The implementation has a deliberately small set of responsibilities:
Payload decides whether the entry point exists, Next.js presents it, and the Giscus GitHub App connects the embed to the public discussion. The fallback link still offers a way to find the conversation if the iframe cannot load.
The website's reusable section contains the heading, explanation, and GitHub fallback link. A small client component mounts the official @giscus/react widget, loads its iframe lazily, passes the active language, and follows the site's resolved light or dark theme. This keeps GitHub's script away from readers who never reach the bottom of an article. The section sits outside the reading-progress target, so scrolling through comments does not affect article progress.
The integration has no server-side Giscus call during page generation. In a browser check, the English and Chinese versions displayed the same post:<ID> term and loaded localized sign-in prompts. I also checked the mobile layout and both Technical and Trading routes. Those checks establish that the embed loads; they are not a claim that a test comment was posted.
The cache problem that appeared at launch
The first deployment exposed a separate issue: the new CMS settings were correct, but a prerendered article still reflected an older configuration. The existing CMS hook could request website cache invalidation only when its shared callback configuration was present. The www domain also redirects to the canonical domain with a 301; a POST sent through that redirect becomes a GET and the invalidation endpoint answers 405. A successful CMS save alone did not prove the public article had refreshed.
Article detail requests now set a 60-second refresh interval for both post data and site configuration. That is a fallback for the comment controls, not instant moderation: after expiry, the next request can still receive the stale page while Next.js regenerates it. I verified the behavior by turning the global switch off and back on; both language versions hid and restored the section without a manual cache purge. The canonical origin remains the correct target for any future push invalidation.
What this choice costs
This is a good fit for a small technical blog whose readers can use GitHub. It asks visitors to use a GitHub account, depends on GitHub Discussions and Giscus availability, and places public conversation data outside the CMS. If the audience broadens beyond GitHub users, the sign-in requirement may be a reason to revisit the decision. For now, the operational boundary is clear: Payload decides whether a post shows comments, the website presents the embed, and GitHub owns the discussion and its moderation tools.
Discussion
Sign in with GitHub to comment. All language versions share this discussion.
View discussions on GitHub