I added a Bluesky comment section to my blog Published on January 24, 2026
You can now view replies to this blog post made on Bluesky directly on this website. Check it out here!
I've always wanted to host a comment section on my site, but it's difficult because the content is statically generated and hosted on a CDN. I could host comments on a separate VPS or cloud service. But maintaining a dynamic web service like this can be expensive and time-consuming — in general, I'm not interested in being an unpaid, part-time DevOps engineer.
Recently, however, I read a blog post by Cory Zue about how he embedded a comment section from Bluesky on his blog. I immediately understood to benefits of this approach. With this approach, Bluesky could handle all of the difficult work involved in managing a social media like account verification, hosting, storage, spam, and moderation. Meanwhile because Bluesky is an open platform with a public API, it's easy to directly embed comments on my own site.
There are other services that could be used for this purpose instead. Notably, I could embed replies from the social media formerly known as Twitter. Or I could use a platform like Disqus or even giscus, which hosts comments on GitHub Discussions. But I see Bluesky as a clearly superior choice among these options. For one, Bluesky is built on top of an open social media platform in AT Proto, meaning it can't easily be taken over by an authoritarian billionaire creep. Moreover, Bluesky is a full-fledged social media platform, which naturally makes it a better option for hosting a conversation than GitHub.
Zue published a standalone package called bluesky-comments that allows embedding comments in a React component as he did. But I decided to build this feature myself instead. Mainly this is because I wanted to make a few styling changes anyway to match the rest of my site. But I also wanted to leave the option open to adding more features in the future, which would be easier to do if I wrote the code myself. The entire implementation is small regardless, amounting to only ~200 LOC between the UI components and API functions.
Initially, I planned to allow people to directly post on Bluesky via my site. This would work by providing an OAuth flow that gives my site permission to post on Bluesky on behalf of the user. I actually did get the auth flow working, but building out a UI for posting and replying to existing comments is difficult to do well. Going down this path quickly leads to building what is essentially a custom Bluesky client, which I didn't have the time or interest in doing right now. Moreover, because the user needs to go through the auth flow and sign-in to their Bluesky account, the process is not really much easier than posting directly on a linked Bluesky post.
Without the requirement of allowing others to directly post on my site, the implementation became much simpler. Essentially, my task was to specify a Bluesky post that corresponds to the article in the site's metadata. Then, when the page loads I fetch the replies to that post from Bluesky, parse the response, and display the results in a simple comment section UI.
As explained in my last post, this site is built using React Server Components and Parcel. The content of my articles are written using MDX, an extension to Markdown that allows directly embedding JavaScript and JSX. In each post, I export a metadata object that I validate using a Zod schema. For instance, the metadata for this post looks like this:
export const metadata = {
... continue reading