You are reading a GitHub Discussion. I wrote it in the zeikar/repozine repository, pressed Start discussion, and about a minute later it was a page on this blog, with its own URL, a table of contents, search and comments.
That is all Repozine does: it turns a repository's Discussions or Issues into a static blog on GitHub Pages.
Why write in a repository
GitHub already has most of what a blog editor needs, and you are probably using it every day.
- A Markdown editor with preview, drag-and-drop images and code blocks
- Labels, which become tags
- Comments and reactions from people who already have an account
- Nothing to host, no database and no admin page to secure
What it lacks is a page that reads like a blog instead of a tracker. Repozine builds that page.
How a post gets published
- You open a discussion in the category you configured, or an issue in issues mode.
- The event starts a GitHub Actions workflow in the same repository.
- At build time, Astro fetches your posts through the GitHub GraphQL API and renders their Markdown into plain HTML.
- The result is deployed to GitHub Pages.
Editing, relabeling or deleting a post, and new comments, rebuild the site the same way. Only posts written by the repository owner are published, so a stranger opening an issue can't put anything on your blog.
What every site gets
- A real URL for every post, and a page for every label
- Full-text search that runs in the browser, powered by Pagefind
- A table of contents that follows along as you read
- Syntax highlighting at build time, in light and dark themes
sitemap.xml,rss.xml, Open Graph cards and article metadata for search engines and link previews- Comments through giscus in discussions mode, or utterances in issues mode
- Dates shown in the reader's time zone
Here is a code block, so you can see the highlighting:
const tagSlug = (name: string): string => {
const slug = name.toLowerCase().replace(/[\s/?#%\\]/g, "-");
return slug === "." || slug === ".." ? slug.replaceAll(".", "-") : slug;
};Discussions or issues?
Both work, and switching is one line in config.json.
| Discussions | Issues | |
|---|---|---|
| Where posts live | One discussion category | Open issues |
| Who can start a post | Maintainers only, with an Announcement-format category | Anyone, but only yours are published |
| Comments | giscus | utterances |
| A closed post leaves the site | On the next build | Closing it rebuilds the site |
This blog runs in discussions mode, because an Announcement-format category keeps the post list clean and leaves issues free for actual issues.
Start your own
Create a repository from the template and fill in config.json:
{
"websiteTitle": "My Notes",
"repoOwner": "your-github-id",
"repoName": "your-repo",
"source": "discussions",
"discussionCategory": "posts",
"googleAnalyticsId": "",
"language": "en"
}Then set the Pages source to GitHub Actions and push. The README covers adding Repozine to an existing repository, comments and search engines.
If you want to see a site with more posts, LeetCode Study publishes more than 150 study notes from its issues.