md0 CMS FOR
HUGO
INTEGRATION GUIDE
md0 connects directly to your GitHub repository and gives your team a visual editor for Hugo content. Every edit creates a GitHub commit. Hugo rebuilds on your hosting platform automatically.
Before You Start
Prerequisites
A Hugo site on GitHub
Any Hugo version works. Your content files need to live somewhere in the repo. Typically the content/ directory, but md0 can point to any path you specify. You do not need to change your Hugo configuration or archetypes.
A GitHub account
md0 uses GitHub OAuth. You grant access to specific repositories rather than your entire account. md0 reads and writes files via the GitHub API. No SSH keys, deploy tokens, or GitHub Apps configuration needed.
An md0 account
Free for public repositories. Sign up at cms.md0.io using GitHub OAuth. No credit card required for public repos.
Step 1
Connect Your GitHub Repository
Sign in with GitHub OAuth
Go to cms.md0.io and click Sign in with GitHub. GitHub presents an authorization screen where you can choose which repositories md0 can access. Limit this to your Hugo repo. md0 does not need access to anything else.
md0 requests read and write access to repository contents. Read access lets md0 display your existing content. Write access lets md0 commit changes when editors save.
Select your Hugo repo
After authentication, pick your Hugo site from the repository list. If it does not appear, go to your GitHub account settings, open Applications, find the md0 OAuth app, and grant it access to the repo.
Once selected, md0 scans the file tree and identifies all .md files. It detects the content/ directory structure and lists subdirectories that look like Hugo content sections, for example content/posts, content/blog, or content/pages.
What md0 detects automatically
md0 reads your repo structure and identifies:
- Directories under
content/that contain markdown files - Frontmatter field names already in use across your existing files
- Whether frontmatter uses YAML (
---), TOML (+++), or JSON format - Your default branch name
md0 uses this to suggest a starting schema based on your existing content structure.
Step 2
Define Your Content Schema
Hugo does not have a built-in schema file. Content structure is implied by your archetypes and templates. md0's schema takes the role of documenting that structure and generating the visual editor form. You build schemas through md0's schema builder interface.
Here is what a schema for a Hugo posts section looks like. The field names must match the front matter keys your Hugo templates read:
Example: Hugo posts collection schema
{
"name": "posts",
"path": "content/posts",
"extension": "md",
"fields": [
{ "name": "title", "type": "text", "required": true },
{ "name": "date", "type": "date" },
{ "name": "draft", "type": "boolean", "default": false },
{ "name": "tags", "type": "multiselect" },
{ "name": "description", "type": "textarea" }
]
}path
This must match the directory Hugo reads content from. For a Hugo posts section at content/posts/, set this to content/posts. Hugo maps this to the URL section /posts/ by default. If you have a custom contentDir in your Hugo config, use that as the base.
extension
Hugo supports both .md and .html content files, but for CMS-managed content you almost always want md. New files created through md0 use this extension. Set it to match your existing Hugo content files.
fields match your Hugo templates
Each md0 field maps to a front matter key that your Hugo templates access via the page variable. Hugo maps front matter keys to template variables automatically:
titlein front matter maps to.Titlein templatesdatemaps to.Datedraftmaps to.Draftdescriptionmaps to.Description- Custom keys like
tagsare available via.Params.tags
Date format matters in Hugo
Hugo expects dates in RFC 3339 format (2024-06-01T00:00:00Z) or the simpler YYYY-MM-DD format (2024-06-01). md0's date picker outputs ISO 8601 dates, which Hugo accepts. Do not use human-readable formats like June 1, 2024. Hugo will reject them and the page will not build.
Step 3
Read Content in Hugo
Hugo reads markdown files from your content/ directory automatically. There is no equivalent to a content collections API call or a filesystem read function. Hugo discovers all content at build time by scanning the directory. This means md0 requires zero changes to your Hugo code.
The front matter fields md0 writes must match what your Hugo templates expect. Here is a typical single post template and how it maps to the md0 schema:
layouts/posts/single.html
{{ define "main" }}
<article>
<h1>{{ .Title }}</h1>
<time datetime="{{ .Date.Format "2006-01-02" }}">
{{ .Date.Format "January 2, 2006" }}
</time>
{{ with .Description }}
<p class="description">{{ . }}</p>
{{ end }}
{{ with .Params.tags }}
<ul class="tags">
{{ range . }}
<li><a href="/tags/{{ . | urlize }}">{{ . }}</a></li>
{{ end }}
</ul>
{{ end }}
<div class="content">
{{ .Content }}
</div>
</article>
{{ end }}How Hugo maps front matter to template variables
.Title, .Date, .Description, .Draft
Hugo maps standard front matter keys to built-in page variables automatically. If md0 writes title: My Post in the front matter, {{ .Title }} in your template outputs My Post. No configuration required.
.Params for custom fields
Non-standard front matter keys (anything not in Hugo's predefined list) are available via .Params. If md0 writes tags: [go, web], access it with {{ .Params.tags }}. The same applies to any custom field you define in your md0 schema.
.Content
Hugo renders the markdown body to HTML and makes it available as .Content. md0 writes the body content in standard GitHub-flavored markdown. Hugo applies your configured markdown renderer (Goldmark by default) to that body at build time.
Section list template: layouts/posts/list.html
{{ define "main" }}
<main>
<h1>{{ .Title }}</h1>
<ul>
{{ range where .Pages "Draft" false }}
<li>
<a href="{{ .Permalink }}">{{ .Title }}</a>
<time datetime="{{ .Date.Format "2006-01-02" }}">
{{ .Date.Format "January 2, 2006" }}
</time>
{{ with .Description }}<p>{{ . }}</p>{{ end }}
</li>
{{ end }}
</ul>
</main>
{{ end }}Filtering draft posts in list templates
Hugo skips files with draft: true by default when building for production. The hugo --buildDrafts flag includes them, but you would not use that flag in your CI/CD build. md0 sets draft: false by default when you define the field with "default": false in your schema.
The where .Pages "Draft" false filter in the list template above is an additional safeguard for list pages. It explicitly excludes drafts from the rendered list even if a draft somehow gets into the build.
What a committed file looks like after an md0 save
--- title: "Getting Started with Go Modules" date: 2024-06-01 draft: false tags: - go - modules description: "A practical walkthrough of Go module initialization and dependency management." --- Go modules replace GOPATH-based dependency management and are the standard for all Go projects since Go 1.16. ## Initializing a module Run `go mod init` in your project root...
Step 4
Deploy and Test
md0 commits to your GitHub repo
When you save a collection schema in md0, it commits a config file to your repository. When an editor saves a post, md0 commits the markdown file to the directory you specified in the schema path. No manual steps. Each save creates a commit visible in your GitHub repo history.
Hugo rebuilds are fast
Hugo is one of the fastest static site generators available. A typical Hugo site rebuilds in under one second locally. On Netlify or Vercel, the build container adds some overhead, but total time from md0 save to live content is typically under 30 seconds for small and medium sites. Large sites with thousands of pages may take longer, but Hugo still outperforms most other generators.
Your team uses md0 as the content interface
Invite team members to your md0 workspace. They see a form-based editor with the fields you defined. No knowledge of Hugo, Go templates, YAML, or Git required. They write in the visual editor and click Save. md0 handles the commit.
Permissions follow GitHub. Team members need write access to the repo to publish through md0. If you want to give someone edit access without full repo write access, use a GitHub branch protection rule and have editors work on a branch that a developer merges to main.
The full workflow
Troubleshooting
Common Issues
Front matter key casing
Hugo maps front matter keys to template variables using case-insensitive matching for built-in variables. For example, title, Title, and TITLE all map to .Title in templates. However, custom parameters accessed via .Params are case-sensitive in some Hugo versions. Keep your md0 field names lowercase to avoid casing issues with .Params.fieldname lookups.
Date format errors
Hugo parses dates strictly. If md0 writes a date that Hugo cannot parse, Hugo either ignores the date or logs a warning depending on the version. md0's date picker outputs ISO 8601 format (2024-06-01), which Hugo accepts. If you are seeing date-related build errors, open the committed file in GitHub and verify the date field looks like this:
--- date: 2024-06-01 ---
Avoid human-readable date formats in the md0 schema. Always use the date field type in md0 rather than a text field for date values.
Draft posts appear in production
Hugo skips draft content automatically when you run hugo without flags. If draft content is appearing in production, check two things:
- 1. Your CI/CD build command is not using
hugo --buildDrafts - 2. The md0 field default for
draftis set tofalsein your schema, nottrue
New posts created through md0 will include draft: false in their front matter if you set the default correctly in the schema. If the field default is missing, Hugo treats the page as published.
Content not appearing after md0 saves
The most likely cause is a path mismatch. If your md0 schema path is content/posts but Hugo reads from content/blog, the files are committed to the wrong directory and Hugo never finds them.
Check the committed file location in GitHub after an md0 save. Navigate to the repository, open the content/ directory, and verify the file landed in the expected subdirectory.
My repo does not appear in md0
GitHub OAuth apps require explicit per-repo permission unless you granted access to all repos. Go to your GitHub account settings, open Applications, find the md0 OAuth app, and grant access to your Hugo repo specifically.
Compatibility
Works With
Netlify
Netlify detects GitHub push events and runs your Hugo build command automatically. A typical md0 save to live content cycle takes under 30 seconds on Netlify, including Hugo build time and CDN propagation.
GitHub Pages with Actions
If you use GitHub Actions to build and deploy Hugo to GitHub Pages, the workflow triggers on push automatically. md0's commits trigger the same workflow. No changes to your .github/workflows/ files are needed.
Hugo Themes
md0 writes standard markdown front matter. Any Hugo theme that reads from the content/ directory works without modification. The theme is unaware of md0. It just sees markdown files with the same front matter structure it always expected.
YAML and TOML Front Matter
md0 detects your existing front matter format and writes new files in the same format. If your Hugo site uses YAML front matter (--- delimiters), new md0 files use YAML. TOML front matter (+++) works the same way.
Keep Going
Next Steps
Learn the visual editor
md0's visual markdown editor outputs standard GitHub-flavored markdown. Editors get formatting controls, image uploads, and a live preview without ever seeing raw markdown or front matter YAML.
Visual markdown editor →Build a more complex schema
Beyond basic text and boolean fields, md0 supports image fields, select dropdowns, multiselect tags, number inputs, and nested objects. Use this to match your Hugo archetypes exactly. The editing experience editors see in md0 mirrors what Hugo expects in the front matter.
Schema builder documentation →Use md0 with other frameworks
md0 works with any static site generator that reads markdown from a Git repository. The GitHub-native approach is the same regardless of the framework.
CONNECT YOUR
HUGO REPO
Free for public repositories. No Hugo config changes. No backend to host. Set up in under five minutes.
CONNECT YOUR HUGO REPO