# Write in Markdown

> YAML frontmatter format for hand-written posts uploaded or published via the CLI.

HTML version: https://blogizi.com/docs/markdown-frontmatter
Markdown version: https://blogizi.com/docs/markdown-frontmatter.md

Write a `.md` file locally with YAML frontmatter, then save it as a draft with `blogizi draft` or publish live with `blogizi publish`. AI coding agents can write the file for you — the CLI only pushes it to Blogizi.

## When to use this

- You already write in your editor (VS Code, Obsidian, etc.)
- You version posts in git alongside your repo
- An AI coding agent drafts the markdown and you push via CLI
- Prefer Obsidian? See the [Obsidian plugin](/docs/obsidian) guide

## Frontmatter template

Every post file starts with YAML frontmatter between `---` delimiters. The CLI parses these fields and sends them to Blogizi when you publish.

```markdown
---
title: "How we built our auth flow"
description: "A walkthrough of the auth decisions we made — sessions, OAuth, and what we'd do differently."
keyword: "indie app authentication"
slug: "how-we-built-our-auth-flow"
status: "draft"
date: "2026-07-21"
readingTime: 0
wordCount: 0
---

Your markdown content starts here. Use `##` and `###` for sections — the page already shows the title, so don't open with a heading that just repeats it.
```

## Field reference

| Field | Required | Notes |
| --- | --- | --- |
| `title` | Yes | Page title and H1 on your blog |
| `description` | Yes | Meta description for SEO and social cards (~150–160 chars) |
| `keyword` | Yes | Primary SEO keyword for the post |
| `slug` | Yes | URL path — lowercase letters, numbers, and hyphens only |
| `status` | No | `draft` or `published` — `blogizi draft` always sets `draft`; `blogizi publish` always sets `published`; `blogizi update` only changes status when set in the file |
| `date` | No | `YYYY-MM-DD` — defaults to today if omitted |
| `readingTime` | No | Leave as `0` — recalculated from content on publish |
| `wordCount` | No | Leave as `0` — recalculated from content on publish |
| `ctaTitle` | No | Per-post CTA title — overrides the project branding CTA when `ctaTitle`, `ctaButtonLabel`, and `ctaButtonUrl` are all set |
| `ctaSubtitle` | No | Per-post CTA subtitle (optional even when CTA is shown) |
| `ctaButtonLabel` | No | Per-post CTA button label |
| `ctaButtonUrl` | No | Per-post CTA button URL |

## Markdown body

Everything after the closing `---` is the article body. Standard Markdown works: headings, lists, links, fenced code blocks with language tags, blockquotes, and images.

```markdown
![Architecture diagram](https://media.blogizi.com/content/your-post-id/1234567890.png)
```

Inline images use standard Markdown syntax. Upload images in the dashboard post editor (rich text or Markdown mode) to get hosted URLs on `media.blogizi.com`, or paste any public HTTPS URL. Cover images (hero + listing cards) are set separately in the dashboard — not in frontmatter.

> **Title is shown separately:** Your blog page renders the title from frontmatter. Avoid opening the body with a heading that simply repeats the title — start with an introduction paragraph or a meaningful section heading instead.

## Upload or publish from the CLI

Authenticate once and select your project (see [CLI publishing](/docs/cli-publishing)), then push any local file:

```sh
blogizi draft path/to/my-post.md
blogizi update path/to/my-post.md
blogizi publish path/to/my-post.md
```

Both `draft` and `publish` create a post; `update` revises an existing post by slug. They recalculate word count and reading time. `blogizi draft` saves a draft; `blogizi publish` makes it live; `blogizi update` keeps visibility unless the file sets `status`.

## Where to store files

Put files anywhere in your repo — `blogizi draft`, `blogizi update`, and `blogizi publish` take an explicit path. A `blogizi-posts/` (or `posts/`) folder in the project root is a convenient convention.

## Not in frontmatter

These fields live on the post record but aren't part of the YAML block — set them in the dashboard after publishing if you need them:

- **Tags** — filtering on your blog homepage and related posts
- **Cover image** — hero image on the article and listing cards (without one, the auto-generated OG image is used on cards)
- **CTA style** — card / banner / minimal / split / accent is project-level (Settings → Branding); only the CTA copy fields above are per-post

> **Warning:** `blogizi draft` and `blogizi publish` each create a **new** post. If a post with the same slug already exists, the API returns a conflict error. To revise an existing article, run `blogizi update` on the same file (or edit it in the dashboard).
