Blog Controller — The /posts/ Listing Page
Configure the /posts/ blog listing page in Dax Pro: pagination, ordering, and post card layout. The blog controller generates the listing automatically from content/posts/*.md. Edit directly in content/posts.md.
What the Blog Controller Is
The blog controller is the file that generates the /posts/ listing page — the archive that shows all your blog articles, paginated. It is a single file in content/:
content/posts.md
When Dax Pro builds the site, it reads this file and generates:
/posts/— the archive page (page 1)/posts/page/2/— page 2, if there are more thanpaginationitems/posts/page/3/— page 3, and so on
Individual blog articles live in content/posts/*.md and each has its own URL (/posts/{slug}/). The controller is what creates the listing page that visitors browse to find those articles.
Without the controller, individual post pages would still be built, but there would be no /posts/ index. Visitors arriving at your domain and clicking "Insights" or "Blog" in the navigation would hit a 404.
The controller is the entry point to your blog. It is required.
This chapter covers:
1. The controller file structure — what each field means
2. How the listing renders — what visitors see
3. Changing pagination — how many posts per page
4. Changing ordering — how posts are sorted
5. Changing the page title and description — the SEO of the listing page
6. The difference between the blog listing and the homepage Insights section — two places posts appear, two different purposes
7. Editing the controller — since Decap CMS does not expose it, only direct edit is available
The Controller File Structure
The default content/posts.md looks like this:
---
layout: "posts-list.dax"
title: "Engineering Publications & Blueprints"
breadcrumb: "Technical Insights"
description: "Architectural analyses, performance benchmarks, and headless content modeling strategies for the modern .NET enterprise ecosystem."
collection: "posts"
pagination: 6
Every field explained:
| Field | Purpose |
|---|---|
layout |
The template used to render the listing. Must be posts-list.dax. Do not change. |
title |
The page's H1 and browser title. |
breadcrumb |
Short label for the breadcrumb bar. |
description |
Meta description for SEO. |
collection |
The folder whose items are listed. Must be posts. Do not change. |
pagination |
Number of posts per page. |
Only four fields are user-editable: title, breadcrumb, description, pagination. Everything else is fixed.
Do not add a body to this file. The controller's body is not rendered. Everything is rendered by the template.
Do not change collection: "posts". The value must match the folder name.
Do not change layout: "posts-list.dax". It must be the blog listing template.
How the Listing Renders
When a visitor opens https://yoursite.com/posts/, Dax Pro renders the posts-list.dax layout with:
1. Page header — breadcrumb and title from the frontmatter
2. Post grid — one card per post, styled as a blog card with image, category, date, read time, title, excerpt, author, and read-more link
3. Pagination — Previous / current / Next, shown only if there are multiple pages
Each post card contains:
image field, or the site's default image from metadata.yaml if the post has no image/posts/{slug}/excerpt (or description as fallback)The cards are clickable. Clicking anywhere on the card goes to /posts/{slug}/.
The grid layout is three columns on desktop, two on tablet, one on mobile. Defined in style.css.
Ordering is by date in descending order. The most recent post appears first.
The Blog Listing vs. the Homepage Insights
Dax Pro shows blog posts in two places:
1. /posts/ — the full blog archive. Shows all posts, paginated. This is the destination for "read all" and "view all" links.
2. / (homepage) — the Insights section. Shows the three most recent posts only. This is a teaser section on the marketing homepage.
These are separate. Editing the blog controller (content/posts.md) changes /posts/. Editing the homepage Insights section (content/index.md → insights) changes the three-post teaser on the homepage.
You cannot control which posts appear on the homepage from the controller. The homepage always shows the three most recent posts by date. To change which posts appear there, change the date field of individual posts.
The blog controller does not control the number of posts on the homepage. That is fixed at three by the home/insights.dax partial.
Why does this distinction matter? Because the two places serve different purposes:
/posts/ — the full archive for readers who want more.If you have only three posts, both sections show the same three posts. If you have twenty, the homepage shows three and /posts/ shows all twenty across four pages.
Changing Pagination
pagination: 6 means six posts per page. With 20 posts and pagination: 6:
/posts/ shows posts 1–6/posts/page/2/ shows posts 7–12/posts/page/3/ shows posts 13–18/posts/page/4/ shows posts 19–20With pagination: 9 and 20 posts:
/posts/ shows posts 1–9/posts/page/2/ shows posts 10–18/posts/page/3/ shows posts 19–20Choosing a value:
| Number of posts | Recommended pagination |
|---|---|
| 1–6 | 6 (no pagination appears) |
| 7–12 | 9 (paginated, 2 pages) |
| 13–24 | 9 (paginated, 3 pages) |
| 25–48 | 12 (paginated, 3–4 pages) |
| 49+ | 12 or 15 (paginated, 4+ pages) |
Rule of thumb: pick a value that fills at least one full page and creates at least two pages when you have more than one page's worth. For small blogs, pagination can look odd — if you have four posts, set pagination: 12 and no pagination appears.
To change pagination:
1. Open content/posts.md in VS Code
2. Change pagination: 6 to your preferred value
3. Save
4. Rebuild
dotnet run -- build
For deployed sites:
git add content/posts.md
git commit -m "Change blog pagination to 9"
git push
Why is the controller not in Decap CMS? The "Posts" collection in Decap CMS exposes individual post files (content/posts/*.md), not the controller file. The controller is configuration, not content, and is left out of the CMS to prevent accidental edits (changing collection: "posts" to another value would break the listing).
Changing Ordering
The listing orders posts by date in descending order. The date field is on each individual post file (content/posts/*.md), not on the controller.
To reorder posts:
1. Open each content/posts/*.md file
2. Change the date field to control the order
3. Rebuild
Example: you have three posts and want them in this order:
1. "Latest Announcement" (should be first)
2. "Technical Deep Dive" (should be second)
3. "Old Tutorial" (should be third)
Set:
content/posts/latest-announcement.md:
date: 2026-05-01
content/posts/technical-deep-dive.md:
date: 2026-04-01
content/posts/old-tutorial.md:
date: 2026-03-01
The dates control order. The most recent appears first.
Editing dates in bulk: if you want to change many posts' dates or ordering, edit the files directly and push once. Editing through the CMS triggers one rebuild per post.
Draft posts and future dates: if you set a post's date to a future date (e.g., 2027-01-01), the post is still published — Dax Pro does not know about "drafts" or "scheduling." It builds whatever is in the folder. To unpublish a post, delete its file. To schedule a post, deploy the file on the scheduled date. There is no built-in scheduling.
If you want draft support: create a _drafts/ folder outside content/ and move posts there until you are ready. Dax Pro only builds files in content/. This is a manual workflow, not automatic.
Changing the Page Title and Description
The listing page's title, breadcrumb, and description are on the controller.
To change via direct edit:
1. Open content/posts.md
2. Update title, breadcrumb, description
3. Rebuild
---
layout: "posts-list.dax"
title: "Our Blog"
breadcrumb: "Blog"
description: "Articles about .NET, static sites, performance, and enterprise web development."
collection: "posts"
pagination: 9
These values appear in:
of /posts/, the browser tab, the OpenGraph title and OpenGraph descriptionOptimizing for SEO:
Editing the Blog Controller
There is no way to edit the blog controller via Decap CMS in the current Dax Pro configuration. The "Posts" collection in Decap CMS is content/posts/ (the individual files). The controller content/posts.md is not exposed.
To change the controller, edit directly:
1. Open content/posts.md in VS Code
2. Edit title, breadcrumb, description, or pagination
3. Save
4. Rebuild
dotnet run -- build
If you want the controller in the CMS, add a file collection to config.yml:
- name: "posts_controller"
label: "📝 Blog Listing"
files:
- name: "posts_listing"
label: "Blog Listing"
file: "content/posts.md"
fields:
- { label: "Layout", name: "layout", widget: "hidden", default: "posts-list.dax" }
- { label: "Title", name: "title", widget: "string" }
- { label: "Breadcrumb", name: "breadcrumb", widget: "string" }
- { label: "Description", name: "description", widget: "text" }
- { label: "Collection", name: "collection", widget: "hidden", default: "posts" }
- { label: "Pagination", name: "pagination", widget: "number", default: 6 }
This is a developer task — see the Developer Guide. For most sites, the controller changes rarely, so direct editing is fine.
Adding and Removing Posts
The controller does not need to be updated when posts are added or removed. It is a dynamic listing — it always shows whatever is in content/posts/.
To add a post:
1. Create content/posts/new-post.md
2. Fill in the frontmatter (title, description, date, etc.)
3. Write the body
4. Rebuild
The post appears in /posts/ automatically at its date-sorted position.
To remove a post:
1. Delete content/posts/old-post.md
2. Rebuild
The post disappears from /posts/ automatically.
To unpublish without deleting: there is no built-in unpublish. Either delete the file or move it outside content/. If you want to keep the content for later, move it to a _archive/ folder outside content/.
The Full Frontmatter Reference
---
layout: "posts-list.dax"
title: "Engineering Publications & Blueprints"
breadcrumb: "Technical Insights"
description: "Architectural analyses, performance benchmarks, and headless content modeling strategies for the modern .NET enterprise ecosystem."
collection: "posts"
pagination: 6
Field-by-field:
| Field | Type | Required | Change? |
|---|---|---|---|
layout |
string | Yes | No — always posts-list.dax |
title |
string | Yes | Yes — your page title |
breadcrumb |
string | No | Yes — short nav label |
description |
string | Yes | Yes — meta description |
collection |
string | Yes | No — always posts |
pagination |
number | Yes | Yes — posts per page |
Total configurable: 4 fields. Everything else is fixed.
Common Blog Controller Mistakes
Mistake 1: Changing collection: "posts".
The value must match the folder name (posts). Changing it to services or any other value breaks the listing.
Mistake 2: Adding a body to the controller.
Anything after the closing --- is ignored. The controller renders through the template.
Mistake 3: Setting pagination: 0.
Zero means zero posts per page. The listing is empty.
Mistake 4: Editing the wrong file for a post change.
If you want to change a post's title, edit content/posts/{slug}.md. If you want to change the pagination, edit content/posts.md. They are different files.
Mistake 5: Deleting the controller.
Without content/posts.md, the /posts/ listing is not generated. Every individual post URL still works, but the archive page is 404.
Mistake 6: Editing the homepage Insights for blog changes.
To change a post's teaser on the homepage, edit the post's date (to control which three appear) or the post's title/excerpt (to change what displays). Editing insights.title on index.md changes the section heading, not the posts.
Mistake 7: Forgetting to rebuild.
Any change requires a build. If you edit and refresh with no visible change, you forgot dotnet run -- build.
Mistake 8: Using uppercase tags on posts.
Uppercase tags break tag pages. Always lowercase.
Verifying the Listing
After editing, verify:
1. URL works — navigate to /posts/. The page loads.
2. Title — browser tab and page H1 match the controller's title.
3. Breadcrumb — shows "Home / {breadcrumb}".
4. Description — view source, confirm matches.
5. Grid — post cards appear in a 3-column grid (desktop).
6. Card content — each card has an image, category/date/read-time meta line, title, excerpt, author, and read-more link.
7. Ordering — most recent post appears first.
8. Pagination — if you have more posts than pagination, pagination links appear at the bottom.
9. Click through — click a card, confirm it goes to /posts/{slug}/.
10. Mobile — resize to mobile. Cards stack vertically, images scale, text wraps.
If a post does not appear:
content/posts/layout: "post.dax"If ordering is wrong:
date field in each postIf pagination is missing:
paginationWhat You Have Now
After this chapter, you can:
/posts/ listing title, breadcrumb, and descriptiondate, descending)/posts/) from the homepage Insightscontent/posts.mdThe blog controller is done. The next chapter covers Blog Post Collections — the individual post files in content/posts/*.md that produce /posts/{slug}/ pages, including their frontmatter, tags, and images.
→ Continue to Blog Post Collections