Aamu.app can be used as a lightweight headless CMS for a static blog. This official blog is built that way: the post metadata lives in an Aamu Database, the article text is written in Aamu Docs, and a build script turns everything into a Hugo site.

The result is a practical publishing workflow. Writers can use Aamu Docs, editors can manage status and metadata in the Database, and the public site stays fast because Hugo generates static HTML that can be hosted almost anywhere.

What we are building

The basic flow looks like this:

Aamu Docs
  -> BlogPost row in Aamu Database
  -> GraphQL API + Docs API
  -> Hugo content files
  -> static blog

The Database row is used for the structured parts of the post: title, slug, author, publish date, status, tags, hero image, and the linked Doc. The Doc is the source of truth for the article body. Hugo is used only at build time to create the public site.

You can see the source code for this blog at https://github.com/AamuApp/aamu-blog.

Why use Aamu.app as a headless CMS?

A traditional CMS can be useful, but it also becomes another product to maintain. If your team already works in Aamu, using Aamu as the CMS keeps writing, metadata, project work, and internal knowledge close together.

This approach is useful when you want:

  • a familiar writing experience through Aamu Docs,

  • structured blog metadata in an Aamu Database,

  • a public site that is static, fast, and easy to host,

  • a build pipeline that can run on your own server, CI, or a static hosting service,

  • GraphQL access to the database rows, and

  • Docs API access to the actual article HTML.

It also gives you a nice separation of responsibilities. Aamu is where the content is written and managed. Hugo is where the public site is generated. Your hosting provider only needs to serve static files.

The ingredients

For a setup like this blog, you need:

  • an Aamu Database created from the aamu-blog template,

  • Aamu Docs for writing the post bodies,

  • a BlogPost table where each row stores post metadata and links to a Doc,

  • a Person table for authors,

  • an API key that can read the database and the linked Docs,

  • Hugo for generating the static site, and

  • some deployment target such as Netlify, Cloudflare Pages, Vercel, or your own server.

Create the blog database

Create a database in Aamu.app with the provided aamu-blog template. The template gives you the basic shape for a blog: a BlogPost table and a Person table.

The BlogPost table is for posts. It stores fields such as title, slug, description, publish date, status, tags, author, hero image, and the Doc reference. The Person table is for post authors.

The important point is that the post body does not need to live in a plain database text field. The preferred workflow is to write the article in Aamu Docs and link that Doc to the BlogPost row.

Write posts in Aamu Docs

Create a new Doc for the article and write the post there. This gives you the normal Aamu Docs writing experience: rich text, headings, lists, links, images, collaboration, snapshots, and source views.

When the post is ready, create or update the matching BlogPost row in the database. Set the title, slug, author, publish date, tags, hero image, and status. Then select the Doc in the row's Doc field.

That Doc is the article source. The build script reads the BlogPost rows through GraphQL and then fetches the linked Doc through the Docs API. If the Doc has HTML content, that HTML becomes the Hugo post body.

What about the Body field?

The Body field is only for manually written or copy-pasted HTML. It is useful as a fallback, or if you really want to manage the post body as raw HTML in the database row.

Do not use the Body field as the normal Doc workflow. In the current Aamu.app UI, you cannot attach a Doc to the Body field. If you want the post to be written in Docs, link the Doc through the row's Doc field instead.

Configure the API key

The build script needs to read published BlogPost rows and fetch the linked Docs. This is done with an API key stored as an environment variable on the machine or CI job that builds the site.

For this blog repository, the useful environment variables are:

API_KEY=your_api_key
AAMU_DB_ID=your_database_id
AAMU_API_BASE_URL=https://your-aamu-host.example

# Optional, depending on your setup:
DOCS_API_KEY=your_docs_api_key
AAMU_PROJECT_ID=your_project_id
GRAPHQL_ENDPOINT=https://api.aamu.app/api/v1/graphql/

Keep API keys on the server side. Do not commit them to Git, do not publish them in frontend JavaScript, and do not paste them into public examples. The static site can be public, but the build credentials should stay private.

Build the Hugo site

The blog repository contains a build script that does the content sync before Hugo runs. The basic command is:

node build-with-graphql.js
hugo --minify

Or as one command:

node build-with-graphql.js && hugo --minify

The script does a few things:

  • queries the BlogPost rows through the GraphQL API,

  • filters for published posts,

  • detects the Doc field in the BlogPost schema,

  • fetches the linked Doc through the Docs API,

  • uses the Doc HTML as the post body,

  • downloads images into the Hugo post folder,

  • writes Hugo-compatible content/posts/.../index.md files, and

  • lets Hugo create the final static site.

The generated Hugo content files are build artifacts. The source of truth is the Aamu Database row plus the linked Doc.

Deployment options

There are several reasonable ways to publish the generated static site.

Static hosting service

You can use a service such as Netlify, Cloudflare Pages, Vercel, or another static host. In that setup, configure the environment variables in the hosting service and use the build command above. A build hook can trigger a new build when content changes.

Your own server

You can also build on your own machine or server and serve the generated files with Nginx or another web server. The official Aamu blog has used a Git-based deployment flow with a bare repository and a post-receive hook. That works well if you like controlling the server yourself, but it is only one option.

CI pipeline

A third option is a CI job. The job checks out the blog repository, sets the Aamu API environment variables, runs the build, and uploads the generated public/ directory to your hosting target.

How this official blog is built

This post itself is written with Aamu Docs. Its metadata is stored in the Aamu blog database. The public page you are reading is generated by Hugo from that data.

That makes the blog a small but real example of Aamu's "one workspace" idea. The same product contains the writing tool, the database, the API surface, and the internal workflow around the content. Hugo and the hosting provider handle the final public website.

Next steps

If you want to build a blog like this:

  1. Fork or clone AamuApp/aamu-blog.

  2. Create an Aamu Database from the aamu-blog template.

  3. Create a Person row for the author.

  4. Create a Doc for your first post.

  5. Create a BlogPost row and link the Doc in the row's Doc field.

  6. Add the API environment variables to your build environment.

  7. Run node build-with-graphql.js && hugo --minify.

  8. Deploy the generated public/ directory.

After that, publishing a post is mostly content work: write in Docs, update the BlogPost metadata, set the status to published, and run the build.