[HN Gopher] Nixtml: Static website and blog generator written in...
       ___________________________________________________________________
        
       Nixtml: Static website and blog generator written in Nix
        
       Author : todsacerdoti
       Score  : 75 points
       Date   : 2025-12-02 14:54 UTC (8 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | JoelMcCracken wrote:
       | neat! I've been moving my site over to heavily use emacs/org for
       | the authoring format and nix for the tooling infrastructure. I'll
       | keep this in mind as a possible tool to help; I don't precisely
       | know what I may still need to do that won't be easily doable with
       | emacs.
        
       | Y_Y wrote:
       | Cool.
       | 
       | After using Nix for a while I got pretty fed up with the
       | (subjective) unintuitiveness of the language+. It wasn't even
       | that I thought it was a bad language, I just couldn't het it to
       | click (and doubly so after the advent of flakes).
       | 
       | All the same it seems to me like if you grok it it's a great fit
       | for constructing recipes for building things reliably that are
       | part of huge dependency trees, and so it's natural that it would
       | be a good website generator too.
       | 
       | + Luckily others shared this issue, and the result was Guix which
       | solves that problem while introducing its own.
        
         | lillecarl wrote:
         | It's a pretty special language, lazy evaluation and very basic
         | types. However after spending the time to learn it to an
         | intermediate level I think it's pretty great.
         | 
         | Flakes are not great however, they're what happens when you
         | "overdo it", sadly the momentum is behind flakes because some
         | UX/DX improvements came along with them (lockfile in repo).
         | 
         | I think the stdenv being built on bash is worse than Nix
         | language.
         | 
         | Module system errors can be very hard to troubleshoot because
         | of lazy eval, sadly I can't see a reasonable solution without
         | worse tradeoffs :(
        
           | Hnus wrote:
           | The flakes were the main UX/DX improvement for me. Before
           | them I honestly could not do anything. The learning curve was
           | so incredibly steep it almost felt like the people behind Nix
           | were being malicious or intentionally gatekeeping. You
           | finally stumble onto something you can at least partly
           | understand, but then the powers that be throw two last
           | obstacles at you like,
           | 
           | First, flakes are "experimental", so you have to enable them.
           | Back then there were like three slightly different CLI
           | commands to do it, and it felt like none worked from like 5
           | tutorial tabs I had open, putting it `experimental-features
           | =` into flake you are trying to switch to does not work
           | obviously.
           | 
           | Then you hit the classic situation where your flake is not
           | committed or staged, so Nix refuses to see it. And instead of
           | telling you that, it prints this abomination of error message
           | "error: path '/nix/store/0ccnxa25whszw7mgbgyzdm4nqc0zwnm8-sou
           | rce/flake.nix' does not exist"
           | (https://determinate.systems/blog/changelog-determinate-
           | nix-3...)
           | 
           | I would not wish learning Nix from zero on my worst enemy,
           | and I say that as someone who uses nix-darwin, devShells,
           | deploy-rs and so on every day. The UX/DX is really bad, but
           | nothing else comes close to its capabilities.
           | 
           | Sorry for rant but without flakes I would not make it.
        
             | entropie wrote:
             | > your flake is not committed or staged
             | 
             | That has nothing to do with flakes. When I add a "module"
             | to my repos its the same. I have to add it the git repos or
             | nix does not "see" it. And yes, its pretty unintuitive.
        
               | Hnus wrote:
               | It actually is specific to flakes. Classic nix commands
               | can see untracked files just fine. Flake evaluation
               | behaves differently because of how it decides which
               | "scheme" to use:
               | 
               | > If the directory is part of a Git repository, then the
               | input will be treated as a `git+file:` URL, otherwise it
               | will be treated as a `path:` url;
               | 
               | This is why untracked or unstaged files disappear when
               | using flakes:
               | 
               | https://github.com/NixOS/nix/blob/ec6789f9dafce41011418fe
               | 6fc...
        
             | MillironX wrote:
             | > The flakes were the main UX/DX improvement for me. Before
             | them I honestly could not do anything.
             | 
             | Agreed. I think flakes are far more intuitive than
             | channels. In a flake everything is declared in the repo
             | it's used in. I still don't understand channels.
             | 
             | For someone who's used to thinking in channels, I suppose
             | flakes would be jarring. For someone (like me) who came
             | from the world of Project.toml and package.json, flakes
             | make a lot of sense.
        
       | NewJazz wrote:
       | Not to be confused with Nixtamal, the processed corn food.
       | 
       | https://en.wikipedia.org/wiki/Nixtamalization
        
         | hardwaregeek wrote:
         | I was wondering if the logo would be a tortilla
        
           | granra wrote:
           | haha I'm afraid it was a total coincidence that it kind of
           | looks like it :D
        
       | mikepurvis wrote:
       | As a nix person, I like this a lot and could see myself using it.
       | My only criticism would be I don't love this kind of thing:
       | "<!DOCTYPE html>\n"         +           html             [
       | (attrs.lang metadata.lang) ]             [               (head [
       | ] [ (partials.head context) ])               (body
       | [                   (attrs.classes [                     "font-
       | sans"                     "bg-white"                   ])
       | 
       | I understand that this is very flexible and powerful, but it
       | immediately makes the templates _highly_ non-portable and
       | requiring of hand-authorship-- fine for a personal blog by a code
       | nerd, but a non-starter for when a designer is involved who will
       | want to use visual tools. I see that right below that there 's
       | also a "normal string templating" option that's closer to
       | conventional jinja2 or the like, but it's ultimately still pretty
       | nix-ified.
       | 
       | It might be worth some ifd [1] to allow a step that pre-processes
       | conventional html + tags template files into the form that can be
       | consumed by nixtml.
       | 
       | [1]: or the still-experimental dynamic derivations:
       | https://fzakaria.com/2025/03/10/an-early-look-at-nix-dynamic...
        
         | granra wrote:
         | I'm the author of nixtml. It's already doing IFD by using
         | python to parse markdown content + metadata and superhtml to
         | format the final HTML (a bit unnecessary, but I liked it while
         | developing it).
         | 
         | I really wanted the templates to just be nix functions. It
         | shouldn't be an issue to pass the context to an external
         | program with `pkgs.runCommand` or something and then read the
         | result (IFD like you mentioned).
         | 
         | Edit: I'm glad to hear you like it :)
        
           | mikepurvis wrote:
           | Yeah, it feels like the more conventional way would be doing
           | the template-filling as a build step, so it's Nix just for
           | the overall structure managing a fixed build graph, and then
           | a per-page Python run to actually fill templates and generate
           | the snippets/pages.
           | 
           | However, if you did want it to be nix all the way down and
           | get more of that juicy dependency granularity, it could be
           | more of a model where content and templates are transformed
           | _upfront_ into Nix source, which is then transformed and
           | combined during evaluation. Obviously this is fairly slow in
           | an IFD world where all that pre-work has to be serialized,
           | but it would be interesting to experiment with what it looks
           | like in a dynamic derivations context.
        
             | granra wrote:
             | Yeah it would probably be more efficient to do the
             | templating as a build step in the derivation that parses
             | the markdown. But after making nixidy[1] I wanted to have a
             | crack at making a static site generator _in nix_. I'm open
             | to expanding it though of course :)
             | 
             | [1]: https://github.com/arnarg/nixidy
        
               | mikepurvis wrote:
               | Oh I can totally understand the impulse on that score. I
               | guess going the way you have at the very least gets you
               | out of some of the annoying handoffs of data between the
               | two worlds, for example putting nix attrsets through
               | toJSON so that they can be picked up on the Python side
               | as template-fill variables.
               | 
               | The ROS 1 world was full of this kind of thing for
               | getting values between Python and CMake and it's truly
               | gross, eg: https://github.com/ros/catkin/blob/noetic-
               | devel/cmake/templa...
        
               | granra wrote:
               | Out of curiousity, having never worked in the business of
               | making websites, what would be accessible to a designer?
               | Jinja2?
        
               | mikepurvis wrote:
               | I haven't for many years [1], but I think the current
               | state of the art is stuff like webflow, silex, pinegrow.
               | None of them _really_ let you directly open, say,
               | django's template files and hack on them though, so
               | there's still a gap where you've got a designer
               | periodically exporting from a visual tool and then their
               | changes having to be ported into the template
               | representation. Obviously it's easy if all they touched
               | was the CSS, but less obvious if markup is involved.
               | 
               | Honestly seems like there's a bit of a gap here. Would be
               | an interesting case for copilot tbh-- here, take the old
               | export and the new export, and make me a PR applying
               | those changes to the templates in this repo.
               | 
               | [1]: I was briefly an intern at a web shop in the late
               | 00s and it was one guy doing Dreamweaver and the rest of
               | us coding PHP around the assets it produced.
        
           | lloeki wrote:
           | > I really wanted the templates to just be nix functions
           | 
           | This feels like Ruby template engines like haml+ and slim++ a
           | lot, or the various xml builders+++ too
           | 
           | + https://github.com/haml/haml
           | 
           | ++ https://slim-template.github.io
           | 
           | +++
           | https://nokogiri.org/rdoc/Nokogiri/XML/Builder.html#class-
           | No...
        
             | mikepurvis wrote:
             | Groovy does something similar with MarkupTemplateEngine; I
             | don't super care for it there either, at least as a
             | mechanism for generating full webpages:
             | 
             | https://docs.groovy-
             | lang.org/docs/groovy-2.5.3/html/document...
             | 
             | It can make a lot more sense as a way to prepare a smaller
             | snippet of XML though, for example an xunit reponse.
        
       | rnhmjoj wrote:
       | There's a more cursed one here: https://rgbcu.be/blog/htmnix. It
       | hijacks the Nix search paths syntax (e.g. import <path> {}) to
       | create html tags.
        
         | JoelMcCracken wrote:
         | oh my god, what a horrible but incredible idea
        
         | granra wrote:
         | I had seen a few of those `__findFile` hackery articles lately
         | and did actually consider doing that but I think having a nice
         | way of adding HTML attributes would've been clunky :p
         | 
         | Edit: although looking at this article it seems to be
         | supported.
        
       | bigbuppo wrote:
       | I don't want to shit on this project, because that's not my
       | intent. My biggest gripe with static site generators in general
       | is that for some reason they require the author to write their
       | pages in something other than plain HTML. It's literally a
       | machine-readable format and yet they all want to mix json, yaml,
       | or something with markdown. And "but the output html would
       | overwrite the input html" isn't really an excuse since they all
       | tend to output to a build directory.
       | 
       | And before someone says, "well you can work on your dream static
       | site generator yourself", rest assured, I am, but I'm also very
       | lazy and usually stop once it gets to a "good enough" state for
       | my own use, but isn't quite ready to share with others.
        
         | granra wrote:
         | Generally I think you have a point when making landing pages or
         | things of that sort. I however basically only use static site
         | generators for blogging and I think markdown/asciidoc/whatever
         | + metadata is nicer for writing content than directly in HTML.
         | 
         | I made nixtml and I take no offence :)
        
           | bigbuppo wrote:
           | I think part of my take stems from the fact that I'm old
           | enough to remember when SGML was supposed to solve all our
           | problems.
        
         | thangalin wrote:
         | > My biggest gripe with static site generators in general is
         | that for some reason they require the author to write their
         | pages in something other than plain HTML.
         | 
         | Being the author of KeenWrite, a Markdown editor that uses YAML
         | variables (for content and metadata), I'm biased, but here's my
         | take:
         | 
         | 1. Writing <p> tags for every paragraph gets tedious.
         | 
         | 2. Markdown is succinct (**bold** vs. <strong>bold</strong>).
         | 
         | 3. Content is easier to edit when not surrounded by angle
         | brackets.
         | 
         | 4. Content is more robust against markup gaffs (e.g., missing
         | closing tags, tag typos).
         | 
         | 5. HTML mixes structural markup with content, making design
         | changes harder.
         | 
         | 6. Markdown's simpler format is more portable to other output
         | formats (PDF, ePub).
         | 
         | 7. Markdown diffs are easier to review, and likely have fewer
         | merge conflicts.
         | 
         | 8. Non-technical contributors are more comfortable with
         | Markdown.
         | 
         | 9. Embedding metadata through meta tags is messier and harder
         | to parse using raw HTML.
         | 
         | Here are a couple of blog posts written in Markdown and
         | converted to HTML using my software:
         | 
         | * https://keenwrite.com/blog/2025/09/08/feature-matrix/
         | 
         | * https://keenwrite.com/blog/2025/10/15/creating-catchy-
         | cover-...
         | 
         | The user manual is a set of Markdown documents converted to PDF
         | (note how the words TeX and ConTeXt and LaTeX are typeset; try
         | to do that with HTML):
         | 
         | * https://keenwrite.com/docs/user-manual.pdf
        
           | bigbuppo wrote:
           | And this is the other big rub with static site generators...
           | they start off as one person's strong opinions as The Right
           | Way To Do It. And that's fine.
           | 
           | 1. Not really 2. Get a better editor 3. Not really, or get a
           | better editor 4. Get a better editor, implement error
           | checking, and use HTML5 5. The idea is to use clean semantic
           | html as the source document and stuff it into a presentation
           | template 6. The source document is clean semantic html 7.
           | Let's be real. 99.99999% of all static site generators are
           | used by one person, generally technically proficient. Merge
           | problems will only happen if you screw up. Also, most modern
           | version control systems aren't storing deltas so merge hell
           | isn't like it was back in the CVS era. 8. Get your non-
           | technical people a better editor 9. Have you explained the
           | quirks of YAML to a non-technical person in one of the
           | Scandinavian countries like Sweden or False? 10. why isn't
           | this formatting properly?
        
           | bigbuppo wrote:
           | Also... KeenWrite looks nice. You made the better editor for
           | markdown.
        
         | hnlmorg wrote:
         | Forgive my ignorance here but if you want to write HTML then
         | what do you gain from a static site generator?
         | 
         | Couldn't you just 'cat' your templates together with a shell
         | script?
        
           | bigbuppo wrote:
           | Starting with clean valid semantic HTML makes it a whole heck
           | of a lot easier to preview in a web browser or editor with a
           | preview feature and gives you quite a few editing options.
           | Granted, there are now live markdown previews in some
           | editors, so this is less of a concern than it was. However,
           | you can easily toss in some CSS in there to make things a
           | little nicer, while the typical markdown preview is going to
           | look like Netscape 2.
           | 
           | As for the templates... those are also HTML. You're just
           | replacing the relevant part of the template's DOM with what
           | you pulled from the source document. Same goes for any boxes
           | on the page you need to stuff with generated content. Your
           | index pages and blog lists are generated from the metadata
           | and other items pulled from the relevant parts of the source
           | documents using the favored html processsing library of the
           | week.
           | 
           | edit: I think I did a terrible job answering your question in
           | my initial reply.
           | 
           | Ultimately, a static site generator is doing what was the way
           | that SGML was envisioned to function... you started with a
           | simpler authoring document and passed it through a processing
           | pipeline that generated a richer SGML document that was
           | eventually output to some sort of output presentation form.
           | My take is that instead of using yaml and markdown for the
           | source documents you just use semantic html, and that
           | templates just use everything that WHATWG has given us with
           | modern HTML instead of that plus a template language.
        
       | badmonster wrote:
       | Using Nix for templating is wild but makes sense - you get
       | reproducible builds, type checking, and function composition for
       | free. The trade-off is portability and designer accessibility.
       | Interesting niche: technical personal blogs where infrastructure-
       | as-code mindset extends to content generation.
        
       | grim_io wrote:
       | I may be an unreasonable outlier, but I absolutely refuse to
       | learn a complex config language.
       | 
       | YAML/TOML? These are the maximum of punishment I'm willing to
       | deal with, as they are quite universal and useful in many
       | situations.
       | 
       | If you need a complex touring complete config, you better use a
       | reasonably popular general purpose language, or I'm not touching
       | it.
        
         | MangoToupe wrote:
         | > you better use a reasonably popular general purpose language
         | 
         | Most languages are horrible at templating, so that's its own
         | world of pain.
        
           | grim_io wrote:
           | What kind of templating are we talking about? HTML or in
           | general?
           | 
           | If we take python, for example, you could use jinja for HTML
           | and composition/inheritance for the general stuff.
           | 
           | That's all django does, and it does it well. I don't see what
           | nix is doing so much better.
           | 
           | Prefer JS/TS? You can have JSX, which is superior in any way
           | compared to this nix-based abomination.
        
       | jebronie wrote:
       | this could have been a couple of lines of simple and maintainable
       | php
        
       ___________________________________________________________________
       (page generated 2025-12-02 23:01 UTC)