Skip to content
YuHaibo
Go back

Adding a Comment System to Astro Blog with Bluesky

Table of contents

Open Table of contents

What this setup does

I wanted comments on a static Astro blog without adding a separate database or a traditional comment service. Bluesky turned out to be a workable middle ground. Every new post creates a discussion thread on Bluesky, and the blog page fetches that thread on the client side and renders it as comments.

The publishing flow

The annoying detail is timing. If you want Bluesky to generate a proper preview card, the article page has to be live first, with valid Open Graph tags in place. That requirement shapes the whole deployment flow, so I handled it with GitHub Actions.

Core workflow

  1. Code lands on main, GitHub Actions builds it, and Cloudflare Pages deploys the site.
  2. A script polls the new post URL until the page returns HTTP 200 and exposes valid og:title and og:image metadata.
  3. After that check passes, the script calls the Bluesky API and creates a post with a manually assembled external embed so the link card looks right.
  4. The script saves the returned post uri and url into src/data/bluesky-comments.json.
  5. GitHub Actions commits that JSON change, which triggers a second deployment. On that second pass, the post step is skipped because the mapping already exists.

Guardrails

Two small checks keep this from doing the wrong thing.

How comments are rendered

Data fetching

I did not use SSR for comments. The rest of the blog is static, and I wanted to keep it that way. Comments load in the browser only when someone opens the page.

  1. The component reads the shared mapping JSON and finds the Bluesky post uri for the current article.
  2. It calls the public Bluesky getPostThread endpoint with a normal browser fetch.
  3. The returned thread is flattened into the fields the UI needs, such as avatar, author name, content, likes, and reposts.

Rendering choices

Why I picked this approach

This approach is plain, but that is the point. I do not need to run a database, store comment records myself, or keep another service alive just for a small personal blog. Bluesky’s public API is enough for this use case, and unlike X, it is still realistic to build on.

The other reason is architectural laziness in the good sense. The blog stays a static site on Cloudflare Pages, and the only dynamic part is loaded when someone actually needs it. That keeps the deployment model simple and the comment system separate from the rest of the content.


Share this post on:
Loading comments...

Previous Post
A Low-Cost YubiKey Alternative for Offline Passkey Backup
Next Post
eSIM Best Practices