Back to News & Insights
Web Development October 14, 2026 · 5 min read

Our content pages are written in two inline markup tokens, and one test follows all 342 internal links

A 63-page content site where the body copy is typed data, not markdown files. One regex, three readers, and the assertion that stops a link to a page that no longer exists from shipping.

Our content pages are written in two inline markup tokens, and one test follows all 342 internal links

Every public page on Nakodo that exists to answer a search is typed data in the repository. Not MDX, not a CMS: 63 objects in src/content, each with a summary, sections of blocks, FAQs, and a list of related pages. Eight block types, 853 blocks in total, and an array that the sitemap, the hub pages, the footer, the structured data and /llms-full.txt all derive from.

The body copy inside those blocks still needs two things markdown gives you for free: a link and a bit of emphasis. This post is about the smallest version of that I could get away with, and the test that makes the links safe.

That comment is the design. Two forms, both of which happen to be real markdown, because the same strings have to serve two audiences: a browser reading a page, and a model reading our llms-full.txt, which is 574,505 bytes of the same content rendered as one markdown document.

You can watch one sentence come out both ways. On the how much to pay YouTubers guide:

One string in one file produced both. No markdown parser, no remark plugin chain, no sanitiser.

The regex has three consumers, and keeping them to three is what keeps the format honest.

Internal links get next/link and client navigation. External links get a new tab and rel="noopener noreferrer". Writers never choose, and never forget, because the string has no slot for that decision.

Meta tags and structured data. Those cannot contain markup at all, so they get the text with the tokens removed:

A FAQ answer is rendered on the page with its links, and the same answer goes into the JSON-LD acceptedAnswer as flat text. One function, so a bold can never leak into a meta description.

Content has 342 internal links in body copy, 296 external ones, 37 of the internal ones pointing at an anchor, and another 43 inside glossary definitions. Nobody is clicking through that by hand after an edit.

resolveLink is the function the "read next" cards already use: give it a path and it returns the page's name and blurb, or null. It knows three kinds of target: a content page, a hand-built page such as the pricing page, and a glossary anchor.

So the same function that renders a link card is the function that validates a link, which means the two cannot disagree. A renamed slug breaks the build in the test rather than shipping a 404 that only a crawler notices. A deleted glossary term does the same, and the anchor case is checked all the way down to the term id: /glossary#cpm only passes while a term with id: "cpm" exists, which is also the id attribute the page renders.

The messages are written as the consequence, not the condition. "/guides/how-to-vet-a-youtube-creator: link to unknown page /glossary#cmp" tells you what to fix. "expected true, got false" tells you to go reading.

And the external branch asserts something small and real, https only, rather than pretending to check more. That is the honest edge of this test, and worth saying out loud: 296 external links are checked for scheme and nothing else. Nothing here knows whether a source has moved since it was cited. A crawl would catch it, and a crawl is a different kind of job with a different failure mode, so it does not belong in a unit test that must pass on a plane.

For search-intent pages, yes, and the links are the reason. Prose in a CMS is a graph of strings pointing at each other with nothing enforcing the arrows. Prose as typed data in the repo means the arrows are checkable, and checking them costs one regex and one 10-line function.

The price is real: writing body copy means editing TypeScript, and a block type you do not have yet means a code change rather than a new paragraph style in an editor. Eight block types in, that has stopped being a cost and started being a feature, because the page can only be built out of pieces that already have a renderer, a markdown form, and a schema mapping. There is no "just this once" HTML anywhere on the guides.

Want to discuss this further?

Book a free strategy call with our team to see how these insights apply to your specific business goals.

Book a consultation