Netdocs
Notice anything different?
Well- this entire site is no longer built with MkDocs. It's now built with something I wrote myself, called Netdocs - a static site generator, written in .NET 11.
Why though?
Honestly? Build performance.
This blog has grown to over 200 posts. And, don't get me wrong - Material for MkDocs is genuinely one of my favorite pieces of open-source software. But, as the post count kept climbing, my local rebuilds got slow enough that it started getting in the way of me actually writing.
So, one evening, I got annoyed enough to do something about it. I wanted something that:
- Built this site fast.
- Ran as a single binary - no Python, Ruby, or Node toolchain to keep happy.
- Could take my existing
docs/folder and build it with little-to-no changes.
I vibe-coded a .NET replacement, pointed it at this site, and kept poking at it until it rendered basically everything the same as before. If you're reading this, it worked.
Before you get any ideas
Netdocs is an AI-generated derivative work. It borrows from - and reuses files from - MkDocs and Material for MkDocs. All the credit for the theme, the compiled CSS/JS, the search, and the overall design goes to Martin Donath (@squidfunk) and everyone who's contributed to Material for MkDocs. Those assets are redistributed unmodified, under the MIT license.
If you want a real, supported, grown-up tool - use Material for MkDocs, and go sponsor it. Netdocs is an evenings-and-weekends project. No warranties, no promises. I have a day job, and I stay busy.
So what does it actually do?
The whole goal was to be a near drop-in replacement for my existing Material for MkDocs
setup. My Markdown builds as-is. The config that used to live in mkdocs.yml now lives in the
Netdocs section of a plain appsettings.json.
Here's roughly how it stacks up:
| Netdocs | Material for MkDocs | Hugo | |
|---|---|---|---|
| Runtime | .NET (single binary) | Python | Go (single binary) |
| Config | appsettings.json |
mkdocs.yml |
hugo.toml |
| Material theme | Built-in | Yes | Bring your own |
| Plugins written in | C# | Python | Go templates |
| Incremental build cache | Yes | No | Yes |
| Parallel rendering | Yes | No | Yes |
| Built-in search | Yes (lunr) | Yes (lunr) | No |
The two things that actually solved my problem: an incremental render cache (only the pages that changed get re-rendered), and parallel rendering (it uses every core, instead of one). A full rebuild of this site now takes a few seconds. Saving a single post while I'm writing is basically instant.
What's new around here
Since it's my own generator now, I added a few things I'd wanted for a while. Two you might actually run into:
Interactive calculators. I write a lot of posts about power draw, costs, and networking. I was tired of hardcoding "at $0.12/kWh, this costs…". So now I can drop a little calculator right into a post, and you can plug in your own numbers:
It's all client-side - type in the boxes and the numbers update. No MkDocs equivalent that I know of; it was one of the first things I built.
Other stuff that got added along the way:
netdocs serve- a dev server that reloads the page when I save. It's most of why writing doesn't feel like a chore anymore.- Built-in deploy -
filesystem,git(gh-pages), ands3publishing are just build config. No separate deploy step. - Offline builds - a toggle that self-hosts every CDN asset (highlight.js, Mermaid, fonts,
emoji) so the whole site runs straight off
file://. - HTML/CSS/JS minification and WebP conversion, as build toggles.
netdocs import- point it at an existingmkdocs.ymland it writes out theappsettings.json.
The plumbing
Under the hood it's a plugin pipeline - Markdown gets preprocessed, rendered (Markdig), dropped into templates (Scriban), and then a few things run at the end (search index, tags, RSS). Plugins are just C# classes that hook into whatever stage they care about.
If you actually want to write one, the Netdocs docs have a build-lifecycle diagram and the full list of events and callbacks - that's the right place for the deep detail, not a blog post.
What's included
Most of the Material/MkDocs plugins I actually depend on have a Netdocs version built right in:
- snippets - reusable includes, with
${param}templating - blog - index, archive, and category pages
- tags - tag pages and a tag index
- table-reader - drop a CSV straight into a Markdown table (this is how my networking hardware tables are built)
- rss - a feed for the blog
- redirects - including slugify-aware ones, so old links don't rot
- glightbox - image lightboxes
- macros, arithmatex (math), social cards, client-side search, and a handful more.
Grabbing it
There are prebuilt binaries on the releases page - no .NET SDK needed.
If you'd rather just run it in a container:
docker run --rm -v ${PWD}:/site \
ghcr.io/xtremeownage/netdocs build --config /site/appsettings.json
Building and serving locally looks about like you'd expect:
netdocs build --config ./appsettings.json
netdocs serve --config ./appsettings.json --port 8000
And in CI, there's a GitHub Action that grabs the native binary for you - no .NET setup step:
- uses: XtremeOwnage/Netdocs@v1
with:
command: build
config: appsettings.json
args: --prod
That last one is, in fact, exactly how this site gets deployed now.
Should you use it?
Probably not - and I mean that in the nicest way possible.
Material for MkDocs is the sensible choice, and I'd point most people there without a second thought. But if you're a .NET person who wants a single-binary generator, or you just want to dig around and see how the thing works - it's all MIT-licensed and the source is right there.
Contributions are welcome. Donations are not - a simple kudos, or a hello in my Discord, is more than enough. Just tag me, because between work and life I can be slow to respond.
And one more time, because it's worth repeating - huge thanks to @squidfunk and the Material for MkDocs project. None of this would exist without their work.