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:
curlorwgetawkgrepsed
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:
--no-backup- do not keep the backup files (.orig.*and.toc.*).--hide-footer- do not write the footer comments with the author and date of the last TOC update.
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.