Accent as a static site generator
Most of what you read about Accent CMS talks about serving – the live server, hot reload, the admin UI. But the same binary is also a static site generator, and for a lot of sites that is all you need. This post is an introduction to that side of Accent: what it does, why it exists, and how to go from a directory of Markdown to a deployable site with a single command.
What “static” means here
A static site generator takes your content – Markdown files, some templates, a few images – and renders it ahead of time into plain HTML, CSS, and assets. There is no application running when a visitor arrives; their browser just downloads files. That is why static sites are fast, cheap to host, and hard to break: there is no server to crash, no database to migrate, and no runtime to patch.
Accent produces exactly this kind of output. You run:
accent build --output ./public
and Accent walks your content directory, renders every page through your
theme, processes your images, generates a sitemap and RSS feed, builds a
client-side search index, and writes the whole thing to ./public. Upload
that folder to any static host – object storage, a CDN, GitHub Pages,
Netlify, your own nginx – and you are live.
One binary, no toolchain
The thing that sets Accent apart from most generators is that it is a
single binary written in Rust. There is no Node install, no Ruby, no
Python virtualenv, no plugin ecosystem to npm install before your first
build. You download one executable and you have the whole system: the
Markdown renderer, the Jinja template engine, image processing, syntax
highlighting, diagram rendering, and search are all compiled in.
That means a build is reproducible and self-contained. The binary you run locally is the binary your CI runs, and it has no hidden dependencies that drift between machines.
The same content, served or built
Accent’s build and serve modes render through the same code path, so
what you preview locally with accent serve is what accent build writes
to disk. You develop against a live server with hot reload:
accent serve --config config.yaml
Save a Markdown file or edit a template, and the browser refreshes itself. When the site looks right, you build it. There is no separate “production renderer” to surprise you – serve-vs-build parity is a first-class concern in Accent, tested explicitly.
What you get in the output
A build is more than raw HTML. From the same content, accent build
emits:
- Rendered pages with your Jinja theme applied, breadcrumbs and navigation resolved from the content hierarchy.
- Processed, resized images in modern formats, generated once at build time and cached.
- A sitemap and RSS feed so search engines and readers can follow along.
- A client-side search index – search works on a purely static host, with no search server behind it.
- Diagrams and syntax-highlighted code, rendered at build time so no JavaScript is required to display them.
This very website is built with accent build and deployed as static
files.
Deploying under a path prefix
If your site does not live at the root of a domain – a GitHub Pages
project site at user.github.io/repo, say, or a reverse-proxy mount –
Accent can rewrite every internal URL to sit under a prefix:
accent build --base-path /repo --output ./public
Page links, theme assets, media, pagination, search, and feeds all move under the prefix together, so nothing 404s once deployed.
Catching broken links before you ship
Static sites fail silently: a mistyped link becomes a 404 that no one sees until a visitor does. Accent can fail the build instead:
accent build --strict-links --output ./public
With --strict-links, Accent resolves every internal link in the build
output and stops the build if one is broken. A bad link becomes a red CI
check, not a shipped 404.
Getting the binary
There is one download per platform, and it contains the full feature set. Your license key decides which tier is unlocked at runtime, and neither building a site nor running the development server needs a key at all – so everything in this post works with an unlicensed binary.
On Linux and macOS the install script picks the right archive for your
platform, checks the SHA-256 checksum (and the GPG signature when gpg is
present), and installs accent into ~/.local/bin – no root, no package
manager:
curl -fsSL https://raw.githubusercontent.com/AccentCMS/accent/main/install.sh | sh
On Windows, the PowerShell equivalent:
irm https://raw.githubusercontent.com/AccentCMS/accent/main/install.ps1 | iex
To pin a version rather than take the latest, pass it through to the
script. Note the -s --: a flag placed after the URL is eaten by curl,
which does not understand it, and never reaches sh.
curl -fsSL https://raw.githubusercontent.com/AccentCMS/accent/main/install.sh | sh -s -- --version v0.23.1
Downloading from the releases page
If you would rather not pipe a script into a shell – a reasonable instinct, and often the policy on a build server – take the archive yourself from the releases page:
| Platform | Archive |
|---|---|
| Linux x86_64 | accent-<version>-x86_64-unknown-linux-gnu.tar.gz |
| Linux ARM64 | accent-<version>-aarch64-unknown-linux-gnu.tar.gz |
| macOS Intel | accent-<version>-x86_64-apple-darwin.tar.gz |
| macOS Apple Silicon | accent-<version>-aarch64-apple-darwin.tar.gz |
| Windows x86_64 | accent-<version>-x86_64-pc-windows-msvc.zip |
| Windows ARM64 | accent-<version>-aarch64-pc-windows-msvc.zip |
Unpack it and put accent somewhere on your PATH:
VERSION=v0.23.1 BASE=https://github.com/AccentCMS/accent/releases/download/$VERSION curl -fsSLO $BASE/accent-$VERSION-x86_64-unknown-linux-gnu.tar.gz tar xzf accent-$VERSION-x86_64-unknown-linux-gnu.tar.gz install -m755 accent ~/.local/bin/accent accent --version
Every release also ships checksums-<version>.txt and a detached
signature checksums-<version>.txt.asc made with the Accent CMS release
key, so you can verify the archive before you run it:
curl -fsSLO https://raw.githubusercontent.com/AccentCMS/accent/main/release-signing-key.asc gpg --import release-signing-key.asc curl -fsSLO $BASE/checksums-$VERSION.txt curl -fsSLO $BASE/checksums-$VERSION.txt.asc gpg --verify checksums-$VERSION.txt.asc checksums-$VERSION.txt sha256sum -c --ignore-missing checksums-$VERSION.txt
Starting from scratch with accent init
You do not need to assemble a project by hand. accent init scaffolds a
complete, buildable site – content, theme, and config.yaml – so your
first accent build produces real output:
# Scaffold a starter site into ./my-site accent init my-site cd my-site # Preview it live, with hot reload accent serve # Build the static output accent build --output ./public
accent init ships more than one starting point. List what is available,
then pick one:
# See the bundled templates accent init --list # Scaffold the full documentation site instead of the simple starter accent init my-docs --docs
The simple starter is a good base for a blog or a small marketing site;
the --docs template gives you the full documentation layout with
navigation and search wired up. Either way you get a directory that builds
on the first try – no missing theme, no empty config.yaml to fill in
before anything renders.
Deploying to GitHub Pages
GitHub Pages is the shortest path from a repository to a live static site, and Accent is built to deploy there cleanly – including the awkward case that trips up most generators.
GitHub Pages serves in one of two shapes, and the difference decides how you build:
- User or organization sites (
username.github.io) serve at the domain root. Nothing special is needed – build as you would for any domain. - Project sites (
username.github.io/repo) serve under a/reposub-path. Every page link, theme asset, media file, and search fetch has to carry that prefix, or the deployed site 404s on its own assets.
Accent handles the project-site case for you. The path component of
--base-url sets the site’s base path, so every internal URL Accent emits
is prefixed to match – no post-build rewriting step:
accent build --output ./public --base-url https://username.github.io/repo
Before you push, preview the prefixed build exactly as it will be served.
accent serve-static reads the resolved base path from the build, so no
extra flags are needed:
accent serve-static --dir ./public # Visit http://127.0.0.1:4403/repo
To automate the deploy, commit a GitHub Actions workflow that installs Accent, builds, and publishes the output:
# .github/workflows/pages.yml name: Deploy to GitHub Pages on: push: branches: [main] permissions: contents: read pages: write id-token: write # Let a running deploy finish rather than cancelling it half-published. concurrency: group: pages cancel-in-progress: false jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - name: Install Accent CMS run: | curl -fsSL https://raw.githubusercontent.com/AccentCMS/accent/main/install.sh | sh -s -- --version v0.23.1 echo "$HOME/.local/bin" >> "$GITHUB_PATH" - name: Build site run: accent build --output ./public --base-url https://username.github.io/repo --strict-links - name: Upload artifact uses: actions/upload-pages-artifact@v5 with: path: ./public deploy: needs: build runs-on: ubuntu-latest environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v5
Pinning the Accent version with --version is deliberate: a CI job that
silently follows the latest release is a build that can change under you
without a commit. Bump it when you choose to.
Then enable Pages in the repository under Settings > Pages and select
GitHub Actions as the source. On the next push to main, the workflow
builds the site and publishes it.
Two Accent touches make this pipeline safe. The --strict-links flag above
fails the build if any internal link is broken, so a bad link stops the
deploy instead of shipping a 404. And whenever a base path is in effect –
as it is for a project site – the build finishes with a conformance check
over its own output: if any emitted page, the search index, or llms.txt
still carries an unprefixed root-absolute URL, the build fails and names
the offending files. You find out at build time, not when a visitor hits a
broken asset on the sub-path. (Both guards are no-ops for a root
deployment, where there is no prefix to get wrong.)
One limitation worth knowing: GitHub Pages cannot set custom response headers, so the security headers Accent’s server would send (CSP, frame options) are absent on Pages. For a content site that is usually fine; if you need those headers, host somewhere that supports them.
Where to go next
The whole loop – scaffold, preview, build, deploy – is free, with no license key. You pay to serve in production, not to build, so you can take a project from an empty directory all the way to a live GitHub Pages site without one:
accent init my-site cd my-site accent build --output ./public --base-url https://username.github.io/repo --strict-links
We will go deeper on templates, content modeling, and other deployment targets in future posts. For now, the documentation covers the full command set, and the news page tracks every release.