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):

terminal
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.

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:

yaml
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

terminal
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:

terminal
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.