---
title: "Markdown TOC Generator"
description: "Make a linked table of contents from the headings in a Markdown file. Pick GitHub or GitLab anchors and the heading levels, then copy the list or download the file with the TOC added."
url: https://findutils.com/text/markdown-toc/
category: text
---

# Markdown TOC Generator

Make a linked table of contents from the headings in a Markdown file. Pick GitHub or GitLab anchors and the heading levels, then copy the list or download the file with the TOC added.

**Use this tool:** [Markdown TOC Generator](https://findutils.com/text/markdown-toc/)

## Programmatic access

- REST id `markdown-toc`: POST https://api.findutils.com/api/tools/markdown-toc/execute (reference: https://findutils.com/api/markdown-toc/)
- MCP tool `markdown_toc` on https://mcp.findutils.com (reference: https://findutils.com/mcp/markdown-toc/)
- Data: The REST API and the MCP tool are a separate path from this page: a call sends the input you include to FindUtils over HTTPS, where it is processed and the result returned. FindUtils does not store that input, and logs the request without its content.

## Why generate a Markdown table of contents?

A long README or design doc needs a table of contents, and writing one by hand is fiddly: every heading has to be turned into the exact anchor the host makes, nested to the right depth, and a second heading with the same text needs its numbered anchor. Get one character wrong and the link goes nowhere. Command-line tools such as doctoc do it, but installing one for a single file is more work than the TOC. This page reads the headings and writes the list with working links.

## Tips

- Put [TOC] on a line of its own where the list should go. Download file with TOC replaces it.
- Use <!-- toc --> to keep the list regenerable: the first run adds <!-- tocstop --> after the list, and every later run replaces what is between the two markers.
- Two headings with the same text get #setup and #setup-1, the way GitHub numbers them. Repeats are counted across every heading, including ones outside the levels you list.
- Lines starting with # inside code blocks are comments, not headings. Ignore code blocks is on by default; the summary says how many were skipped.
- A numbered list nests with at least 3 spaces, because Markdown needs them under "1. ". With 2 spaces chosen, numbered items use 3.
- Front matter between --- lines at the top of the file is left alone, and the TOC goes after it.

## Frequently Asked Questions

### How do I make a table of contents for a Markdown file?

Paste the Markdown into this page or drop the .md file on it. The table of contents appears at once with links to each heading. Copy it, or download the file with the list inserted at a [TOC] marker or after the first heading.

### Do the links work on GitHub?

Yes, with the GitHub slug style, which is the default. Anchors follow GitHub's rules: lowercase, punctuation removed, each space turned into a hyphen, and a repeated heading numbered -1, -2. Inline code and links in a heading are read as their text, the way GitHub renders them.

### What is different about GitLab anchors?

GitLab also lowercases and removes punctuation, but then turns a run of hyphens into a single one. So ## Setup & Install links to #setup--install on GitHub and #setup-install on GitLab. Choose the GitLab style for a GitLab repository.

### How are duplicate headings handled?

The second heading with the same text gets -1, the third -2, and so on: two ## Setup headings link to #setup and #setup-1. The count covers every heading in the file, including ones outside the levels you list, which is how GitHub numbers them.

### Are headings inside code blocks skipped?

Yes, while Ignore code blocks is on, which is the default. A # line inside a fenced (``` or ~~~) or indented code block is a comment, not a heading, so it is left out, and the summary says how many were skipped.

### Where does the TOC go in the downloaded file?

At your marker if there is one: a [TOC] line is replaced, and <!-- toc --> is filled and closed with <!-- tocstop --> so a later run can replace it. With no marker, the TOC goes right after a first-line title heading, or at the top after any front matter.

### Does it keep the TOC up to date?

No. It is a one-shot insert: nothing watches the file or runs on commit. When the headings change, run the page again; with the <!-- toc --> marker, the old list is replaced in place.

### Can I use it from a script or an AI client?

Yes. The same function is the markdown_toc tool on the FindUtils MCP server and a REST endpoint at api.findutils.com. It takes the Markdown and the same options as this page, and returns the TOC, the document with the TOC inserted, and the list of headings with their anchors.

### Is my Markdown uploaded?

Not on this page. The headings are read and the list is built in your browser, and the text you paste is not sent anywhere. The REST API and MCP tool are a separate path: a call sends the input you include to FindUtils over HTTPS, where it is processed and the result returned. FindUtils does not store that input, and logs the request without its content.

## Related Tools

- [Markdown Table Generator](https://findutils.com/text/markdown-table-generator/)
- [Markdown Previewer](https://findutils.com/developers/markdown-previewer/)
- [Markdown to HTML](https://findutils.com/convert/markdown-to-html/)
- [Markdown to Word](https://findutils.com/convert/markdown-to-word/)
- [DOCX to Markdown](https://findutils.com/convert/docx-to-markdown/)
- [HTML to Markdown](https://findutils.com/convert/html-to-markdown/)
