Series: contentstore

An Article Is a File

By John Hardy
January 11, 2026 | Series: contentstore

I treat each article as a single Markdown file inside its own folder because I want the archive to stay inspectable and durable. A reader can open the file and see the full text in a stable shape, which keeps the record legible years later. You can also clone the archive and read it in plain text when the build changes.

Each entry lives in its own folder. The folder path carries the date and slug. The file carries the writing, so URLs stay aligned with edits.

Open article.md in any entry and you always see the same two-section structure. A YAML block sits at the top and the Markdown body follows, which keeps the writing distinct from the data surface.

---
title: "The Shape of the Archive"
summary: "How this blog organises itself on disk instead of inside a database. The path does the work."
series: genesis
tags: [tooling, publishing]
status: published
thumbnail: hero.jpg
---

Here is where the writing begins…

Everything above the divider is frontmatter for indexing, and everything below it carries the published text. The build reads the YAML block to assemble lists for series and tags, then renders the body as the article page. That keeps selection mechanical and keeps templates focused on structure.

That pairing is the reason each permalink stays stable and reviewable even when the build changes.

Some values appear in both places because each surface has a job. Titles and summaries belong in lists, while the article uses its own headline. A summary can stay out of the body so indexes stay concise. That keeps index pages tight while the article stays expansive. It also keeps readers from re-reading the same text in two places.

From a tooling point of view this keeps articles easy to work with. The file reads cleanly in a text editor. The metadata parses cleanly in small scripts. Git diffs stay tight enough to scan in seconds.

For readers this means the permalink remains stable and the record stays open to inspection. For me it means a predictable build and a file I can review years later. That durability is the payoff of treating the file system as the source.

The Article Body

By John Hardy
January 11, 2026 | Series: contentstore

Frontmatter defines an article for the build, but the body carries the meaning for readers. It is the section a reader actually meets, so I treat it as the record that must survive every build. Everything below the YAML block exists to be read, and that focus drives the format and the discipline. The body holds the text and keeps links and code beside the media, so the file stays readable before and after the build touches it.

Markdown keeps the text close to plain language. Paragraphs and headings read the same in a terminal or a diff viewer, so the file stays legible wherever it travels. That consistency lets me review drafts without leaving the file. That stability is why I keep the body in Markdown even as the rest of the system shifts. I begin the body with the title and date line so the file stands on its own and the reader can orient without metadata. Sections use normal Markdown headings, which keeps the body free of page and layout syntax.

Layout lives in templates and the body stays focused on narrative structure. I add section breaks to serve the argument, and the template controls how headings appear on screen. Links point to published URLs and stay explicit in the prose, which keeps filesystem paths out of the body. Code blocks use fenced Markdown and avoid inline tooling because the code exists to be read. Syntax highlighting can happen in the browser when it helps.

Images and other assets sit in the same folder as the article, and the Markdown references them by relative path so the entry stays self-contained when the folder moves. The build copies that folder into the public tree and keeps the same structure in place, which keeps images working in indexes and on their own page. The body avoids embedding logic and keeps lazy loading in templates, while the Markdown stays presentation-agnostic and media framing stays in the layout layer. That boundary keeps the writing stable, so I can edit a paragraph or add a code block without worrying about the rest of the system. The file remains text with attachments, and the build system turns it into a page.

These posts describe the system that publishes them, and they do so in the same format as every other article. That keeps the documentation inside the pipeline, and the body serves as evidence of the approach. When the build changes, the archive stays reliable. If an idea cannot live inside Markdown with links and headings, I treat that as a design problem and fix the system until it can. The body is my promise to readers: it stays readable even if the build disappears.

Assets

By John Hardy
January 11, 2026 | Series: contentstore

An article rarely stands on text alone. Screenshots and diagrams sit beside photos and small media files in the same unit of work as the writing they support, and I keep them together for that reason. In this system those files live beside the article that references them so each entry stays complete and portable. A typical article folder looks like this:

content/blog/2026/01/11/03-assets/
  article.md
  assets/
    tree-structure.webp
    hero.jpg

article.md holds the writing and the assets/ folder holds the attachments. There is no shared media pool and no global upload directory, so each article carries its own supporting files. That choice keeps the archive legible on disk and makes it obvious which files belong to which entry.

A cloned copy stays complete because each article carries its own attachments.

The Markdown body names assets by relative path, and the build resolves those paths to absolute URLs anchored to the article permalink. The source stays clean, and the output stays stable. That keeps links predictable when the archive grows. It also keeps review simple because the path stays visible in the prose.

![Tree structure diagram](./assets/tree-structure.webp "Tree structure diagram")

Because the image sits next to the file that references it, the source stays stable when the folder moves or the repository gets cloned. The build converts that source path into a permalink-safe URL so the same image works whether the article appears on its own page or inside an index. That behaviour makes it safe to reorganise the archive without breaking links.

Images serve different roles across the site, and some get promoted into indexes as thumbnails while others appear inline as diagrams or screenshots. That distinction comes from frontmatter and templates, and the Markdown only names the file. The writing stays focused on content while the presentation stays elsewhere. I can change that presentation later without touching the text.

The same approach applies to any other asset, including animated images and small videos as well as data files or reference PDFs. The build copies the assets/ folder into the output tree and preserves the on-disk structure while emitting absolute URLs in rendered HTML. That keeps the output predictable and the source portable.

Nothing in the article body needs to know how the site will present an image because it only names a file. The template decides whether that file becomes responsive or lazy-loaded, and how it gets styled for the page. That keeps the body light while the layout carries the polish.

That boundary keeps the writing stable, so I can edit a paragraph or add a code block without worrying about the rest of the system even when I drop in a diagram. The file remains text with attachments and the build system turns it into a page. The body stays clean because it has to, and it is the place where all of this meets a human reader.

Tree structure diagram
Tree structure diagram

Tags: assets

Frontmatter as Data

By John Hardy
January 11, 2026 | Series: contentstore

I write the body for readers and use frontmatter so the build can work without reading it. Everything above the YAML divider supports indexing and ordering along with layout. The build reads this small structured block and stops. That boundary keeps the prose for people while the data stays available to the pipeline.

A typical frontmatter block looks like this:

title: "An Article Is a File"
summary: "How each entry in this blog reduces to a single Markdown file. The body stays human, the header stays machine."
series: genesis
tags: [publishing, process, tooling, structure]
status: published
thumbnail: assets/hero.jpg

Those fields form the row for this article in the site's internal table. Titles and summaries let index pages render without scraping prose, and the series value places the article inside a forward-moving narrative. Tags attach the entry to topics, and status controls visibility. The thumbnail gives lists a concrete image.

This separation lets writing and indexing evolve independently. A list title may not match the heading inside the article, and a summary may never appear in the prose. I keep that duplication because it keeps each surface predictable and keeps the body readable even when the index logic changes.

It keeps the voice in the body intact when I revise the indexing rules.

From a tooling perspective this keeps the pipeline simple. Scripts parse YAML and collect rows, then apply filters and sorts without reading the body. That keeps selection mechanical and prevents hidden inference. Everything that participates in queries and lists lives in one place, in a form that stays stable even as the writing changes.

Tags: frontmatter

Years