Skip to content
All posts

Go to market · Behind the scenes

How we publish this blog

Posts are Markdown files in the product repository, published by opening a pull request. Here is the whole workflow, including the checks that stop a broken post reaching the site.

This blog has no content management system, no admin login, and no publish button. A post is a Markdown file in the same repository as the product, and publishing one is opening a pull request.

That sounds like a constraint imposed by engineers on everyone else. It is closer to the opposite: it means a post gets a preview URL before anyone sees it, a review thread attached to the words, and a build that refuses to ship a file with a mistake in it.

The whole workflow

  1. Add a file to apps/web/content/blog/, named for the URL you want. pricing-that-says-no.md becomes /blog/pricing-that-says-no.
  2. Copy the front matter block from _template.md in the same folder and fill it in.
  3. Write the post underneath it in ordinary Markdown.
  4. Open a pull request.
  5. Read your post on the preview URL the build posts back.
  6. Merge. The merge is the deploy.

Step five is the one worth pausing on. The preview is the real page, on the real stylesheet, at the real width, with your typography and your line breaks. It is not a rendering approximation in an editor pane.

The front matter

Every post starts with a block that describes it:

---
title: How we publish this blog
summary: One or two sentences. This is the card blurb and the search description.
date: 2026-08-27
author: The Sprig team
authorRole: Go to market
topics: [Go to market, Behind the scenes]
---

Two of those fields do more work than they look like they do.

summary is not optional and has no fallback. It is what a reader sees on the index card, what a search engine prints under the link, and what gets pulled into a social preview. If it were allowed to default to the first paragraph, every post would ship with a description nobody wrote.

topics drives the filter on the index and the related posts at the bottom of every article. Two posts sharing a topic point at each other without anyone maintaining a list.

There is also a draft: true flag. A draft is visible on the preview build and absent from the live site, which is how you circulate something for comment before it is finished.

What the build refuses

The checks exist because the failures they catch are all quiet ones - a post that looks fine in the pull request and is wrong on the site.

MistakeWhat happens
A misspelled front matter key, like topic: for topics:Build fails and names the file
A missing summaryBuild fails
A related: slug pointing at a post that does not existBuild fails
A date like 2026-02-31Build fails
A file name with a capital letter or a space in itBuild fails
An image with no alt textBuild fails

None of these are style opinions. Each one is a thing that, left alone, produces a page that renders without complaint and is wrong for every reader.

What you can write

Ordinary Markdown, deliberately limited to what the site can draw: headings, lists, links, bold and italic, blockquotes, code blocks, tables, images, and horizontal rules.

Anything outside that set renders as its literal text rather than disappearing, so a construct we do not support is visible in the preview instead of silently dropping a paragraph.

Why not a CMS

A content management system would remove the pull request, and the pull request is where most of the value is. A post gets the same review as a code change: someone reads it, comments on a specific line, and the history of what changed and why is attached to the post for as long as it exists.

It also means the blog cannot drift away from the product. When the pricing page stops saying "preview" because billing exists, the post that linked to it is in the same repository as the change, and the link is checked by the same build.

Want us to write about something? Tell us.