I Wanted a Simpler Static Site Generator, So I Created Neyx

  • Thread starter Thread starter Seyyed Ali Mohammadiyeh (Max Base)
  • Start date Start date
S

Seyyed Ali Mohammadiyeh (Max Base)

Guest
I have used static site generators for quite a while.

Jekyll was one of the first ones that felt solid to me and the core idea still makes sense. You write some Markdown with a bit of front matter then a few layouts and after the build you end up with a site.

The trouble showed up once things got bigger. Adding posts and includes and plugins and custom code and image stuff and pagination just slowed everything down. Changing a template meant saving then waiting then refreshing and it got old fast when I was tweaking CSS or layouts. Hugo is quick and there are others like Eleventy or Astro that handle the speed side better yet that was not the only thing I wanted to fix.

I also wanted fewer dependencies so old projects would not break two years later when I opened them again. That is what led me to create NeyX.

The requirements were simple enough. Markdown input simple templates a dev server that rebuilds on its own and plain static output at the end. Usual blog features like tags pagination RSS and search should just be there without hunting for plugins each time.

At some point the build starts taking long enough that you notice it.

You change one thing.

Save.

Wait.

Refresh.

Fix another small thing.

Wait again.

That gets annoying pretty quickly when you are working on templates or CSS.

Of course, this is not something every static site generator suffers from. Hugo is very fast, for example. There are also Eleventy, Zola, Astro, and many other tools that solve this problem in different ways.

But speed was only part of what I wanted to improve.

I also wanted the project itself to be simpler.

Fewer dependencies. Fewer things to install. Fewer things that can stop working because I opened an old project two years later.

That is what made me create NeyX.

What I Was Looking For​


My requirements were honestly pretty basic.

I wanted to write Markdown.

I wanted simple HTML templates.

I wanted a development server with automatic rebuilds.

I wanted the generated site to be plain static files.

And I wanted the usual blog features without having to install a plugin for every single one.

Things like:

  • tags
  • pagination
  • RSS
  • Atom
  • sitemap
  • search
  • responsive images

Nothing unusual.

I just did not want to build the whole toolchain around those features myself.

Example Projects​


conference: a five-page conference site built entirely from data/ files: speakers, schedule, ticket tiers, and sponsors.


personal-website: a single-language personal site: plain pages, a data-driven nav, no dates or collections.


blog: a single-language blog: tags, pagination, drafts, RSS/Atom feeds, a table of contents.


docs-site: documentation: a sidebar from a data file, nested pages, client-side search, raw HTML mixed with Markdown.


blog-i18n: the same blog in English, Persian, and Arabic: automatic RTL, hreflang links between translated posts, per-language collections.


Starting a Project​


A new NeyX project starts like this:

Code:
neyx new my-blog
cd my-blog
neyx dev

The generated directory is small:

Code:
my-blog/
├── neyx.config.yml
├── content/
├── layouts/
├── assets/
├── data/
└── static/

I liked this immediately because I did not need to read much before understanding it.

  • content/ is your Markdown.
  • layouts/ contains the templates.
  • assets/ is for images, CSS, and similar files.
  • data/ contains YAML or JSON that you want to access from templates.
  • static/ is for files that should simply be copied to the final output.

And then there is one config file:

Code:
neyx.config.yml

That is pretty much the whole project structure.

Routing Is Based on Files​


There is no separate routing file for normal pages.

If I create:

Code:
content/about.md

I get:

Code:
/about/

If I create:

Code:
content/posts/hello.md

I get:

Code:
/posts/hello/

And if I create:

Code:
content/projects/index.md

I get:

Code:
/projects/

I prefer this kind of routing for blogs and documentation sites.

The folder structure already tells me where the page should live. I do not really want another layer of configuration for that.

Writing a Post​


A post looks like what you would expect:

Code:
---
title: "Hello World"
description: "My first post"
date: "2026-09-24"
tags: ["programming", "web"]
layout: post
---

# Hello World

This is my first post.

If you have used Jekyll, Hugo, or most other static site generators, this is familiar territory.

The front matter is available in the template, and the Markdown becomes the page content.

A simple layout can be very small:

Code:
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>{{ title }}</title>
</head>
<body>

  <article>
    <h1>{{ title }}</h1>
    {{ & content }}
  </article>

</body>
</html>

There is nothing special going on here.

{{ title }} comes from the front matter.

{{ & content }} prints the rendered Markdown content.

That is enough for a basic page.

The Template Syntax Did Not Take Long to Learn​


One thing that can make a static site generator annoying is its template language.

I do not want to spend a day learning another DSL just to print a list of posts.

NeyX keeps the syntax fairly small.

Conditions look like this:

Code:
{{ if description }}
  <p>{{ description }}</p>
{{ end }}

Loops are simple too:

Code:
<ul>
{{ each post in posts }}
  <li>
    <a href="{{ post.url }}">{{ post.title }}</a>
  </li>
{{ end }}
</ul>

You can include other templates:

Code:
{{ include "_header.html" }}

And there are filters for the usual small transformations:

Code:
{{ title | upper }}

or:

Code:
{{ title | truncate 50 }}

There is more available, but I did not need most of it at the beginning.

That is something I appreciate in tools like this.

I want to learn the rest when I need it, not before I can render my first page.

Development Speed Matters More Than Benchmark Numbers​


This was probably my biggest frustration with some of my older static sites.

People often talk about build performance in terms of milliseconds or pages per second.

For me, the more important question is simpler:

Do I notice the build?

If I am editing a template and saving every few seconds, even a small delay becomes annoying.

With NeyX I run:

Code:
neyx dev

and leave it running.

It builds the site, serves it locally, watches the project, and rebuilds when something changes.

That is what I want from development mode.

I do not want another watcher.

I do not want another package just for reloads.

I do not want to run three commands in three terminals to work on a blog.

The development build also skips some heavier production work, such as responsive image generation, which helps keep the edit and refresh cycle fast.

This sounds like a small thing, but it changes how the tool feels while you are actually using it.

Production Is Just a Build​


When I am ready to generate the final site:

Code:
neyx build

By default, the output goes into:

Code:
dist/

That directory contains the final website.

No server code.

No runtime.

No database.

Just files.

Something like:

Code:
dist/
├── index.html
├── about/
├── posts/
├── assets/
├── sitemap.xml
├── feed.xml
├── atom.xml
└── robots.txt

At that point NeyX does not matter anymore.

You can serve the result anywhere that can serve static files.

That is still one of the nicest things about static sites.

The build tool disappears after the build.

The Built-In Stuff Is What I Ended Up Liking Most​


At first I was mostly interested in the basic workflow.

Markdown in, HTML out.

But after using it more, the built-in features became more interesting.

A real blog usually needs more than pages.

You need a sitemap.

You probably want RSS.

Maybe Atom too.

You want tag pages.

Eventually you want pagination.

Then search.

Then you realize the 4 MB image you uploaded should probably not be sent to every phone at full size.

None of these problems is difficult.

But they keep coming back.

With some generators, you solve each one separately. Find a plugin. Configure it. Hope it still works after the next upgrade.

NeyX handles a lot of this during a normal build.

It can generate:

Code:
sitemap.xml
feed.xml
atom.xml
robots.txt
search-index.json
api/pages.json
api/posts.json

That is useful because I do not have to think about most of it.

Tags Work the Way I Expected​


If a post has:

Code:
tags: ["linux", "programming"]

NeyX can generate pages for those tags.

You can also define more taxonomy fields in the config:

Code:
taxonomies:
  - tags
  - categories

There is not much more to explain.

And I think that is a good thing.

Tags are not supposed to be an engineering project.

Search Without a Search Service​


I also liked the way search works.

For a personal site or documentation project, I usually do not need a full search backend.

NeyX generates a static search index:

Code:
search-index.json

Then you can add a small search UI:

Code:
<input id="q" placeholder="Search">
<ul id="results"></ul>

<script src="/assets/neyx-search.js"></script>
<script>
  NeyXSearch('#q', '#results')
</script>

The browser loads the index and filters it locally.

That is probably not what I would use for a website with millions of pages, but for a normal blog it is more than enough.

No API key.

No external account.

No separate search server.

I like solutions that match the size of the problem.

Image Handling Is Built In Too​


Images are another place where static sites can quietly collect extra tooling.

You start with a few JPEGs.

Then you want smaller versions.

Then you add an image script.

Then that script becomes another dependency.

NeyX can generate responsive variants for JPEG and PNG files in the assets directory.

It can produce sizes such as:

Code:
480px
960px
1440px

You can also skip that processing when you do not need it:

Code:
neyx build --no-images

This is especially useful during development when there is no reason to keep regenerating image variants after every small change.

neyx check Is More Useful Than It Sounds​


One command I did not expect to care much about was:

Code:
neyx check

It checks the generated site for problems such as broken internal links, missing assets, duplicate routes, and images without alt text.

The nice thing about this is that static site generators can happily produce broken websites.

The HTML can be perfectly valid while this link is wrong:

Code:
<a href="/proejcts/">Projects</a>

The build succeeded.

The page exists.

The link is still broken.

So being able to run:

Code:
neyx build
neyx check

before publishing is useful.

It is simple, but I use tools like this more than fancy features.

There Is Also a Route Debugger​


If something is going to the wrong URL, there is:

Code:
neyx routes

It shows the routes NeyX calculated, along with the source file and layout.

This is another one of those features that sounds boring until you need it.

If I expected:

Code:
/blog/hello/

and somehow created:

Code:
/posts/blog/hello/

I would rather run one command than stare at my directory structure for twenty minutes.

There are a few other utilities too:

Code:
neyx doctor
neyx info
neyx benchmark

doctor checks the project setup.

info shows project information.

benchmark runs repeated builds and reports timing.

They are not things a visitor will ever see, but they make the development side nicer.

The Single Binary Approach Helps​


NeyX is written in Salam Programming Language and distributed as a native binary.

I do not think the implementation language is the important part for most users.

The useful part is the result.

The project does not need a runtime just to run the generator.

My mental model is basically:

Code:
Markdown + YAML + HTML
          |
        NeyX
          |
      Static files

That also makes deployment and CI straightforward.

Install the binary.

Run:

Code:
neyx build

Deploy dist/.

There is not much else to maintain.

For me, that is a big part of the appeal.

What About Hugo, Jekyll, Eleventy, and the Others?​


I do not think NeyX makes every other static site generator obsolete.

That would be a silly claim.

Jekyll has a huge history and still fits very naturally into the GitHub Pages ecosystem.

Hugo is extremely fast and has a large community.

Eleventy is flexible and works well if you are already comfortable in the JavaScript ecosystem.

Those things matter.

If I had an existing Hugo site that worked perfectly, I would not rewrite it just for fun.

The reason NeyX caught my attention was simpler.

I wanted something small.

I wanted one tool.

I wanted the usual blog features already there.

And I wanted the development loop to stay fast.

That is it.

Multi-Language Support Was a Nice Extra​


I was also surprised by the multilingual support.

You can define languages in the config:

Code:
languages:
  - en
  - fa
  - ar

Then structure the content like this:

Code:
content/
├── en/
│   └── posts/
├── fa/
│   └── posts/
└── ar/
    └── posts/

The routes get language prefixes automatically.

Templates also receive the current language and text direction, so Persian and Arabic pages can use RTL without having to manually configure each page.

Translated pages can also be linked together.

This is the kind of feature I might not need on every site, but when I do need it, I definitely do not want to invent the whole thing myself.

The Daily Workflow Is Small​


After using NeyX for a while, this is basically what I need to remember.

Start development:

Code:
neyx dev

Create a new post:

Code:
neyx new post "My New Post"

Build the site:

Code:
neyx build

Check it:

Code:
neyx check

If the routing looks wrong:

Code:
neyx routes

That covers most of the normal workflow.

The rest is just writing Markdown and editing HTML.

Which, for me, is what a static site generator should mostly get out of the way and let me do.

If you want to look through the project or try it yourself, it is here:

https://github.com/BaseMax/neyx
 

Thread statistics

Created
Seyyed Ali Mohammadiyeh (Max Base),
Replies
0
Views
19
Back
Top