Cookie Consent

I use cookies to understand how my website is used. This data is collected and processed directly by me, not shared with any third parties, and helps us improve our services. See my privacy and cookie policies for more details.

Frontmatter Field Classification & params.mt Migration Proposal

Generated 2026-06-21. Companion file: yaml-migration-map.xlsx. Source inventory: yaml-frontmatter-audit.*.

Every field currently used across the 267 index files, classified against Hugo’s reserved front-matter fields (verified against the Hugo 0.163.3 documentation), with a proposed target for everything that isn’t Hugo’s.

How Hugo decides what’s “its own”

Hugo reserves a fixed set of front-matter field names (title, date, type, layout, etc.). Reserved names are case-insensitive — Hugo lowercases keys on read, so lastMod resolves to Hugo’s lastmod and Layout resolves to layout. Any name not on that list is a custom field, and since Hugo 0.123 custom fields are only exposed to templates if they live under the params key. That single rule explains both buckets below: legitimate Hugo fields stay at the top level, and everything else belongs under params.mt.

1. Hugo reserved fields — keep at top level (14)

These are genuine Hugo fields and should remain exactly where they are, as siblings of params.

FieldType seenKeep / action
titlestringkeep
descriptionstring / nullkeep
keywordsstring / nullkeep (Hugo expects a list, but tolerates a string)
draftboolkeep
datedatetime / datekeep — normalise to one format (audit conflict)
lastModdate / datetimekeep — resolves to lastmod; normalise (audit conflict)
publishDatedatetime / nullkeep
expiryDatenull onlykeep — Hugo field, currently always empty; omit when unused
typestringkeep — blog / page / section / briefings (drives templates)
layoutstring / nullkeep
linkTitlestringkeep
slugstringkeep
urlnull onlykeep — Hugo field, currently always empty; omit when unused
paramsmapkeep — this is the container that will hold params.mt

One fix in this group: Layout (capital L) on tags/_index.md is the same field as layout (Hugo lowercases it). Rename it to lowercase to remove the duplicate.

2. Custom fields sitting at the top level — in error (4 blocks)

These are not Hugo fields, yet they sit at the top level where, under current Hugo, templates can’t reliably read them. They should move under params.mt.

Current→ ProposedWhere it occurs
seoTitleparams.mt.seoTitle217 files
hero.*params.mt.hero.*about/_index.md
videoSpotlight.*params.mt.videoSpotlight.*root _index.md
showVideoparams.mt.showVideoroot _index.md

3. Custom data already under params — move into params.mt.* (the bulk)

This is the real mariothomas.com data. The proposal dissolves the redundant params.content wrapper — since params.mt now is the content namespace — promoting its children up one level, while keeping logical sub-groups (author, thumb, audio, links) intact.

Current path→ Proposed
params.content.typeparams.mt.type
params.content.categoryparams.mt.category
params.content.featuredparams.mt.featured
params.content.file / .mime / .timeparams.mt.file / .mime / .time
params.content.url / .url_titleparams.mt.url / .url_title
params.content.x / .x_titleparams.mt.x / .x_title
params.content.location / .location_titleparams.mt.location / .location_title
params.content.thumb.*params.mt.thumb.* (src, alt, caption, type, width, height, version)
params.author.{name,email}params.mt.author.{name,email}
params.audio.{source,duration,size,text}params.mt.audio.*
params.links[] + .links_title / .links_descriptionparams.mt.links[] + .links_title / .links_description
params.abstractparams.mt.abstract
params.hideparams.mt.hide
params.tags / params.categoriesparams.mt.tags / params.mt.categories — see note

4. Drop (2)

Always-null, and duplicate the Hugo top-level fields of the same name:

One decision to make: tags & categories

params.tags and params.categories are the one ambiguous case. If you want them to remain plain data (labels you render yourself), params.mt.tags / params.mt.categories is correct. But if you want Hugo’s taxonomy system — term pages, /tags/... listings, .GetTerms — those keys must sit at the top level (tags: / categories:), not under params at all. You already have a tags taxonomy and a tags/ section, so this is worth resolving deliberately rather than defaulting.

Summary of the move

Of the 71 distinct key paths: 14 stay as Hugo fields (plus the Layoutlayout casing fix), 2 are dropped, and the remaining 54 consolidate under params.mt.* — whether they were mis-placed at the top level (seoTitle, hero, videoSpotlight, showVideo) or already living in params (content.*, author, audio, links, etc.). The proposed params.mt tree is laid out on the second sheet of the workbook.

The colour-coded, file-count-weighted version of this mapping — every path, its classification, and its target — is in yaml-migration-map.xlsx.