HomeGuides › Mermaid Gantt Charts: Syntax, Gotchas, and Round-Tripping to a Real Editor

Mermaid Gantt Charts: Syntax, Gotchas, and Round-Tripping to a Real Editor

Mermaid gantt blocks render natively in GitHub, GitLab, Notion and Obsidian, which makes them the easiest way to put a schedule where the work already lives — in the repo, reviewable in a pull request. They are also miserable to edit: move one date and you re-derive every after chain downstream by hand. This covers the syntax field by field, a worked example you can paste into a README, the traps that render perfectly while being wrong, and the missing step — editing visually and getting the text back.

· gantts.app

The same schedule as text and as bars:
gantt dateFormat YYYY-MM-DD excludes weekends section Design Research :done, res, 2026-01-05, 5d Wireframes :active, wf, after res, 8d Sign-off :milestone, 2026-01-23, 0d Design Research (done) after res Renders natively in GitHub, GitLab, Notion and Obsidian.

The syntax in one pass

A gantt block opens with the keyword gantt and a few header lines, then section headings with task lines under them. Indentation is convention, not grammar.

A task line is a name, a colon, then comma-separated fields:

Task name :tag, id, start, duration

Header lines worth knowing: dateFormat (how dates in your file are written), excludes weekends, title, and axisFormat (how the axis is labelled, in strftime-style codes). Fields are classified by shape rather than strictly by position, which is why :done, res, 2026-01-05, 5d and :res, done, 2026-01-05, 5d both work.

Task A:id a1:2026-03-02:5dTaskidStartDuration
Every field on a Mermaid task line, and which ones are optional.

A worked example you can paste into a README

A complete, valid block for real work — migrating a public API from v1 to v2. It uses sections, absolute dates, after chains, every tag, a milestone and excluded weekends. Paste it into a fenced mermaid block in any GitHub Markdown file and it renders.

gantt
      title API v2 Migration
      dateFormat YYYY-MM-DD
      axisFormat %b %d
      excludes weekends
      
      section Discovery
      Audit v1 endpoints   :done, audit, 2026-03-02, 5d
      Draft OpenAPI spec   :done, spec, after audit, 4d
      Spec review          :active, review, after spec, 2d
      
      section Build
      Auth service         :crit, auth, after review, 10d
      Resource endpoints   :res, after auth, 12d
      Client SDK regen     :sdk, after res, 3d
      
      section Cutover
      Staging soak         :soak, after sdk, 5d
      Public beta          :milestone, beta, 2026-05-04, 0d
      Deprecate v1         :dep, after beta, 2w

Reading it line by line:

  • dateFormat YYYY-MM-DD tells Mermaid how to read the dates you typed. Input format, not output — changing it does not change the axis.
  • axisFormat %b %d is the output side: the axis reads "Mar 02" rather than a full ISO date. Use %V for week numbers on anything longer than a quarter.
  • excludes weekends makes every bar step over Saturday and Sunday, for the whole diagram — there is no per-task override.
  • Audit v1 endpoints :done, audit, 2026-03-02, 5d — tag, id, an absolute start (a Monday), five days. Durations are inclusive of the start day, so this ends Friday 6 March.
  • after audit means "start when audit finishes" — with weekends excluded, Monday 9 March, not Saturday the 7th.
  • :crit, auth, ... paints the bar in the critical-path colour. Note paints — see the limits below.
  • Resource endpoints :res, after auth, 12d has no tag at all; the first field is just an id. Untagged means upcoming work.
  • Public beta :milestone, beta, 2026-05-04, 0d is a zero-length marker on a fixed date. Milestones get an id like anything else, so after beta on the last line is legal.
  • 2w is two weeks. Mermaid also accepts h and m, rarely useful here.

The blank lines between sections are decorative — Mermaid ignores them, and so does our importer. Keep them anyway; a 40-task block without them is unreadable in a diff.

Task-line reference

Every field and modifier, what it does, and what it looks like in practice.

Field or modifierExampleWhat it does
idauditA bare word naming the task so after can refer to it. No spaces or punctuation. Optional unless something depends on the task.
afterafter auditStarts when the named task finishes. FS only, no lag. Accepts several ids — after a b waits for the later.
done:done, audit, …Renders the bar as completed. No percentage — 100% and "basically finished" look identical.
active:active, review, …Renders the bar as in progress. Again with no number attached.
crit:crit, auth, …Colours the bar as critical. An assertion you type, not something Mermaid derives — nothing checks it against the dependency chain.
milestone:milestone, beta, …Draws a diamond instead of a bar. Pair it with 0d.
Duration units5d · 2w · 8hDays, weeks, hours (also m). Inclusive of the start day: 5d from Monday ends Friday.
End date2026-03-02, 2026-03-06A second date instead of a duration, for an externally fixed finish.
dateFormatdateFormat YYYY-MM-DDHow dates in the file are parsed. Header line, once per diagram.
axisFormataxisFormat %b %dHow the axis is labelled, in strftime codes. Purely cosmetic.
excludesexcludes weekendsNon-working days. Also takes specific dates (excludes 2026-04-06) and weekday names. Whole diagram.

Four things that will bite you

1. Durations are inclusive of the start day. 5d from Monday the 5th runs to Friday the 9th, not the 10th. An off-by-one here shifts every task in the file and still renders perfectly, which is the worst possible failure mode: nothing looks broken.

2. after plus excludes weekends is where the real bugs live. If a predecessor ends on a Friday, its successor starts on the Monday — not Saturday. Any tool that resolves after by adding one calendar day will quietly put tasks on weekends in a file that explicitly forbids them, and every downstream date drifts from there. Ours did this, briefly. The fix routes the arithmetic through the working calendar so the import agrees with what Mermaid draws, and the test guarding it asserts the property rather than specific dates: no derived start or end may land on an excluded day. Dates you typed by hand are left where you put them, weekend or not — silently moving an author's explicit date is the wrong kind of helpful.

3. There is no escaping. A colon starts the field list and a comma separates fields, so Phase 2: design, review becomes a task called "Phase 2" with garbage fields. Keep colons, commas and semicolons out of names; on export we substitute spaces rather than emit a line that will not parse.

4. An unparseable duration silently becomes zero. Write 3dd and you get a zero-length bar rather than an error. Scan for invisible tasks after a bulk edit.

Finish → StartABB waits for AStart → StartABB waits for AFinish → FinishABB waits for AStart → FinishABB waits for A
"after" is finish-to-start with zero lag — the only link type the format has.

The limits of a diagram format

Mermaid gantt is a rendering language, not a scheduling engine, and the difference shows up the moment you want the chart to answer a question rather than illustrate an answer.

None of that makes it a bad format. It makes it a publishing format — good for showing a schedule, useless for deriving one. Which is why the round trip matters.

Editing visually, then pasting the text back

Plenty of tools render Mermaid. What has been missing is the other direction — dragging bars and getting the syntax back out.

  1. Paste or open your diagram in gantts.app — a .mmd, or a .md with a fenced block. It detects a gantt block by content, not extension.
  2. Drag, link and re-date it like any other chart. excludes weekends switches the working calendar on, so the dates it produces agree with the file it came from.
  3. Export ▸ Mermaid gantt, copy, paste back into your README, commit the diff.

The trip is lossy in a known, boring way. Progress maps 100% to done and 1–99% to active on the way out; active comes back in as 50% — a guess you are told about in a warning rather than left to find in a status report. Links that cannot be written as after — anything with a lag, or any SS/FF/SF relationship — fall back to absolute dates, which stay correct even though they stop being maintainable.

One deliberate asymmetry, because it is not a bug: crit is exported but never imported. On the way out it is derived — the editor computed the critical path from the dependency graph, so the tag is true when written. On the way in it is a word somebody typed in a file that may be weeks stale, and trusting it would let an old diagram paint a non-critical chain red. So it is written and then ignored: the critical path you see after an import was recalculated, not asserted.

A useful side effect if you draft schedules with an LLM: ask for Mermaid gantt syntax, paste the answer in, and you have an editable chart with a computed critical path — no API key, no backend.

undefined

Templates that use this

Frequently asked questions

How do I write a Gantt chart in Mermaid?

Start the block with gantt, add dateFormat YYYY-MM-DD, then section headings with task lines under them in the form "Name :tag, id, start, duration" — for example "Research :done, res, 2026-01-05, 5d".

Does 5d in Mermaid include the start day?

Yes. A 5d task starting Monday the 5th finishes Friday the 9th. This inclusive counting is the most common source of off-by-one errors, and it produces a diagram that renders perfectly while every date is wrong by one day per task.

How do dependencies work in Mermaid gantt?

Use "after someId" as the start field. It is always finish-to-start with no lag — start-to-start, finish-to-finish and lags cannot be expressed. You can name several predecessors, as in "after a b", and the task waits for the later of them.

Does after skip weekends?

It does when the diagram declares "excludes weekends". A successor to a task ending on a Friday starts on the Monday, and its duration is counted in working days. Tools that resolve after by adding one calendar day put tasks on Saturdays in a file that forbids them.

Can Mermaid calculate the critical path?

No. The crit tag is a colour you apply by hand; nothing in Mermaid walks the dependency graph or computes float. That is why gantts.app exports crit but ignores it on import — criticality is recalculated from the dependencies rather than trusted from a possibly stale file.

Can I convert a Mermaid gantt chart into an editable chart?

Yes. Open the .mmd or the Markdown file in gantts.app, edit it visually, then use Export ▸ Mermaid gantt to copy the updated syntax back out.

Try it on your own plan

gantts.app is a free Gantt chart maker that runs in your browser. No account, no download, no watermark on exports.

Open the free editor