How this website is built
This whole site is built with Nera. Nothing here is special-cased — it's the same generator and the same public plugins you'd install. Here's the full recipe.
Scaffolded like any site
It started with the nera CLI, which scaffolds a site whose one Nera dependency is
@nera-static/nera (it brings the @nera-static/core engine):
npx @nera-static/nera new nera-website
Thirteen plugins, each doing one thing
| Plugin | Job | Config |
|---|---|---|
plugin-navigation |
Header + footer menus with active states | config/navigation.yaml |
plugin-tags |
Tutorial tags + per-language /tutorials/tags/* pages |
config/tags.yaml |
plugin-search |
Per-language client-side search index + box | config/search.yaml |
plugin-page-pagination |
Prev/next in docs and tutorials | config/page-pagination.yaml |
plugin-canonical-links |
Canonical <link> tags for SEO |
config/canonical-links.yaml |
plugin-link-attributes |
External links open in a new tab | config/link-attributes.yaml |
plugin-code-blocks |
Build-time syntax highlighting with a copy button | config/code-blocks.yaml |
plugin-stacks |
The homepage feature grid, one Markdown file per feature in pages/stacks/home-features/ (see Reusable content blocks) |
— |
tutorials-list (local) |
Builds app.tutorials for the index |
— |
llms-txt (local) |
llms.txt, llms-full.txt and a .md per page for AI assistants |
config/llms-txt.yaml |
skill-zip (local) |
The Nera skill as a zip for claude.ai and Claude Desktop | — |
heading-ids (local) |
An id on every h2–h4, so sections can be linked |
— |
table-scroll (local) |
Wraps every Markdown table in a .table-scroll box, so wide tables scroll on phones |
— |
The five local plugins — tutorials-list, llms-txt, skill-zip,
heading-ids and table-scroll — live in plugins/, set with folders.plugins in config/app.yaml. llms-txt and
skill-zip write files rather than data, and hand them to the build through the
getAssets hook (see Write your own local plugin).
skill-zip reads the skill from the installed @nera-static/nera, so the
download always matches the CLI the site builds with. Most of the others have
their own tutorial in this section, if you want the details.
Order matters — canonical links and search run last
Search builds its index from the final state of every page, so it has to run after
everything else. Canonical links have to come after plugin-tags too, or the tag
pages it generates get no canonical link — and alphabetically, canonical-links
would run before tags. config/plugin-order.yaml says so:
plugin-order:
- end:
- plugin-canonical-links
- plugin-search
Everything else runs alphabetically in between. This is the one place plugin ordering is load-bearing on this site.
Templates we own
Plugins that ship views were published into theme/views/vendor/ with commands like
npx nera-navigation. Those copies are ours to edit and style — nothing important
is hidden inside node_modules.
Content is just Markdown
Every page you're reading is a Markdown file under pages/ with a layout in its
frontmatter. The docs are pages/docs/*.md; this tutorial is
pages/tutorials/how-this-site-is-built.md. Folders become URLs; no routing config
exists.
Build
npm run build # pages/ -> public/
Checks and deploy
Every push to main and every pull request against it runs
.github/workflows/test.yml on Node 22 and 24 — the same commands you can run
locally:
npm ci
npm run lint # eslint
npm test # node --test on the tests beside the local plugins
npm run validate # nera validate: layouts, includes, frontmatter
npm run build -- --check # nera build --check
--check looks at the built public/ for accessibility, privacy and
legal-notice problems and reports what it finds. Findings are warnings, so they
fail the run only for a rule that config/validate.yaml promotes to an error.
A push to main then runs .github/workflows/deploy.yml: npm ci,
npm run build, and public/ is published to GitHub Pages — the site you are
reading at nera.js.org.
That's the entire stack: Markdown in, static HTML out, plugins for the rest. If you've read the other tutorials in this section, you've now seen every piece of it in isolation — this is just all of them together.