gh-md-toc

Easy TOC creation for GitHub README.md

v0.10.0 GitHub

Installation

macOS (manual installation):

curl https://raw.githubusercontent.com/ekalinin/github-markdown-toc/master/gh-md-toc -o gh-md-toc
chmod a+x gh-md-toc

Linux (manual installation):

wget https://raw.githubusercontent.com/ekalinin/github-markdown-toc/master/gh-md-toc
chmod a+x gh-md-toc

Linux or macOS, using Basher (gh-md-toc will be available in the PATH):

basher install ekalinin/github-markdown-toc

Why

gh-md-toc is for you if you want to generate a TOC (table of contents) for a README.md or a GitHub wiki page without installing additional software. It is an attempt to fix the problem from github/issues/215.

It needs only standard tools:

Usage

gh-md-toc works with markdown from stdin, local files, and pages on github.com. Local files and stdin are rendered through the GitHub API, see GitHub token if you hit its rate limit.

STDIN

Pass - to read markdown from stdin:

$ cat README.md | ./gh-md-toc -
* [gh-md-toc](#gh-md-toc)
* [Table of contents](#table-of-contents)
* [Installation](#installation)
* [Usage](#usage)
   * [STDIN](#stdin)
   * [Local files](#local-files)
   * [Remote files](#remote-files)
   * [Multiple files](#multiple-files)
...

Local files

Pass a path to a markdown file:

$ ./gh-md-toc README.md

Table of Contents
=================

* [gh-md-toc](#gh-md-toc)
* [Table of contents](#table-of-contents)
* [Installation](#installation)
* [Usage](#usage)
   * [STDIN](#stdin)
   * [Local files](#local-files)
...
* [Docker](#docker)
   * [Local](#local)
   * [Public](#public)

<!-- Created by https://github.com/ekalinin/github-markdown-toc -->

Remote files

Pass a URL instead of a path, for example a GitHub wiki page:

$ ./gh-md-toc https://github.com/ekalinin/nodeenv/wiki/Who-Uses-Nodeenv

Table of Contents
=================

* [Who Uses Nodeenv?](#who-uses-nodeenv)
   * [edx](#edx)
   * [OpenStack](#openstack)
   * [HSReplay.net](#hsreplaynet)
   * [pre-commit.com](#pre-commitcom)
   * [sailing-channels.com](#sailing-channelscom)
   * [Galaxy](#galaxy)
   * [Lambdas in Python with Serverless.com](#lambdas-in-python-with-serverlesscom)

<!-- Created by https://github.com/ekalinin/github-markdown-toc -->

That's all. Copy the result into your README.md, or redirect it to a file with > toc.md.

Multiple files

Pass several files or URLs, local and remote ones can be combined. Each link is prefixed with its source:

$ ./gh-md-toc README.md https://github.com/ekalinin/nodeenv/wiki/Who-Uses-Nodeenv

* [gh-md-toc](README.md#gh-md-toc)
* [Table of contents](README.md#table-of-contents)
* [Installation](README.md#installation)
...
   * [Public](README.md#public)

* [Who Uses Nodeenv?](https://github.com/ekalinin/nodeenv/wiki/Who-Uses-Nodeenv#who-uses-nodeenv)
   * [edx](https://github.com/ekalinin/nodeenv/wiki/Who-Uses-Nodeenv#edx)
   * [OpenStack](https://github.com/ekalinin/nodeenv/wiki/Who-Uses-Nodeenv#openstack)
   * [HSReplay.net](https://github.com/ekalinin/nodeenv/wiki/Who-Uses-Nodeenv#hsreplaynet)
   * [pre-commit.com](https://github.com/ekalinin/nodeenv/wiki/Who-Uses-Nodeenv#pre-commitcom)
   * [sailing-channels.com](https://github.com/ekalinin/nodeenv/wiki/Who-Uses-Nodeenv#sailing-channelscom)
   * [Galaxy](https://github.com/ekalinin/nodeenv/wiki/Who-Uses-Nodeenv#galaxy)
   * [Lambdas in Python with Serverless.com](https://github.com/ekalinin/nodeenv/wiki/Who-Uses-Nodeenv#lambdas-in-python-with-serverlesscom)

<!-- Created by https://github.com/ekalinin/github-markdown-toc -->

Auto insert and update TOC

Put these two lines into a local file where the TOC should be:

<!--ts-->
<!--te-->

And run:

$ ./gh-md-toc --insert README.md

Table of Contents
=================

* [My project](#my-project)
   * [Installation](#installation)
   * [Usage](#usage)
      * [Options](#options)
   * [License](#license)
Found markers

!! TOC was added into: 'README.md'
!! Origin version of the file: 'README.md.orig.2026-09-27_112342'
!! TOC added into a separate file: 'README.md.toc.2026-09-27_112342'


<!-- Created by https://github.com/ekalinin/github-markdown-toc -->

The file now contains:

<!--ts-->
* [My project](#my-project)
   * [Installation](#installation)
   * [Usage](#usage)
      * [Options](#options)
   * [License](#license)

<!-- Created by https://github.com/ekalinin/github-markdown-toc -->
<!-- Added by: user, at: Sun Sep 27 11:23:42 UTC 2026 -->

<!--te-->

When the file changes, run the same command again to refresh the TOC. Options for --insert:

GitHub Actions

Keep the TOC up to date on every push to the file:

on:
  push:
    branches: [main]
    paths: ['foo.md']

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v7
      - run: |
          curl https://raw.githubusercontent.com/ekalinin/github-markdown-toc/master/gh-md-toc -o gh-md-toc
          chmod a+x gh-md-toc
          ./gh-md-toc --insert --no-backup --hide-footer foo.md
          rm gh-md-toc
      - uses: stefanzweifel/git-auto-commit-action@v7
        with:
          commit_message: Auto update markdown TOC

permissions: contents: write lets the default GITHUB_TOKEN push the updated file.

GitHub token

Without a token, the GitHub API limits how many files you can process per hour. When you hit the limit, gh-md-toc prints:

Parsing local markdown file requires access to github API
Error: You exceeded the hourly limit. See: https://developer.github.com/v3/#rate-limiting
or place GitHub auth token here: /home/user/token.txt

Create a token at github.com/settings/tokens and pass it as an environment variable:

GH_TOC_TOKEN=<your token> ./gh-md-toc README.md

Or put it into token.txt next to the gh-md-toc script:

echo "<your token>" > token.txt
./gh-md-toc README.md

Docker

Public image on Docker Hub:

docker pull evkalinin/gh-md-toc:0.10.0
docker run -it evkalinin/gh-md-toc:0.10.0 https://github.com/ekalinin/nodeenv/wiki/Who-Uses-Nodeenv

Or build the image from the repository's Dockerfile:

docker build -t markdown-toc-generator .

Run it on a URL:

docker run -it markdown-toc-generator https://github.com/ekalinin/nodeenv/wiki/Who-Uses-Nodeenv

Run it on a local file, sharing its directory as a volume:

docker run -it -v "$PWD":/data markdown-toc-generator /data/README.md

Windows

gh-md-toc is a Bash script. On Windows, use github-markdown-toc.go, a Go implementation without dependencies that can also process files in parallel.