Slug Collision Simulator
Find duplicate Markdown heading IDs before they break deep links
Paste or open multiple Markdown documents and instantly see where GitHub-style heading slugs would clash. Add as many documents as you like, with line-accurate hit lists for every conflict. Runs entirely in your browser.
Potential slug collisions
Slugs that repeat across documents or differ across headings.#introduction
Appears in 2 document(s), 2 heading(s) total.
- guide.mdL1“Introduction”
- api.mdL1“Introduction”
#getting-started
Appears in 2 document(s), 2 heading(s) total.
- guide.mdL5“Getting started”
- api.mdL5“Getting started”
How to use the slug collision simulator
- Each panel represents one Markdown document. Rename the label to match the file you're testing (e.g.,
guide.md). - Paste headings or full Markdown into each panel, or click the file icon to open a
.mdfrom disk. - Add or remove panels with the Add document button or the trash icon — there's no hard limit.
- The Potential slug collisions panel updates live: every slug that repeats across documents (or differs only by heading title) is flagged with line numbers.
Why slug collisions matter
A Markdown heading like ## Getting Started becomes the anchor #getting-started. Inside a single GitHub README, two identical headings get auto-suffixed (#getting-started, #getting-started-1). That suffix is document-local and does not survive merging — so the moment you concatenate two files, you get either:
- Silent duplicates — the second occurrence wins, the first becomes unreachable.
- Renumbered anchors — every deep link that pointed to the original ID now goes to the wrong section.
Either way, links break. The simulator surfaces the problem before publication.
Real scenarios this catches
- Migrating a multi-file docs repo to a single-page docs site. Both
installation.mdandupgrade.mdmay have a## Prerequisitesheading. The simulator flags the collision; you rename one to## Prerequisites (upgrade)and ship. - Stitching chapter files for a static site. A book or course built from per-chapter Markdown often has
## Summaryin every chapter. The simulator shows all of them at once. - Merging release notes from two repos. Each repo's CHANGELOG.md probably has a
## [Unreleased]heading. When merging, decide whether to scope the slug (## Frontend Unreleased) or to keep the files separate on the rendered site. - Cross-file deep links. If your team uses
[See Configuration in api.md](api.md#configuration)patterns, this tool helps confirm the target ID will still resolve after a docs reorg.
How the slug algorithm works
"Getting Started!" → "getting-started"
Step by step:
- Lowercase the heading text.
- Strip everything that isn't a word character, space, or hyphen.
- Collapse runs of whitespace into single hyphens.
- Collapse runs of hyphens into single hyphens.
- Trim leading and trailing hyphens.
That matches GitHub's renderer closely enough for cross-file work. If your downstream platform uses a different algorithm (e.g., Docusaurus's emoji-stripping rules, or Jekyll's kramdown), spot-check a few headings before relying on the result.
Strategies for resolving collisions
| Strategy | When to use |
|---|---|
| Rename to add context | Public docs where descriptive titles help |
Add explicit {#custom-id} anchors | Stable URLs that must not change |
| Place each file under its own route | Sites where pages stay separate (Docusaurus) |
| Scope by section (folder-as-prefix) | Sphinx, MkDocs material themes |
Accept GitHub's -1 suffix | Single-file READMEs only |
Companion tools
- Markdown Slug Generator — see slugs for a single document with TOC.
- Markdown Heading Audit — ensure each file's outline is valid first.
- Markdown Merge & Split — actually combine the files once collisions are resolved.
Privacy & data
The slug algorithm and collision detection both run in your browser. Document contents stay on your machine.
Frequently asked questions
- A slug is the URL-safe ID derived from a Markdown heading (for example, `Getting started` → `getting-started`). A collision happens when two headings produce the same slug — either within a document or across documents that will be merged into one site. GitHub auto-disambiguates within a single file by appending `-1`, `-2`, but cross-file collisions silently break deep links.
- Mostly when you're merging content. Examples: stitching multiple READMEs into a microsite, importing chapters from separate `.md` files into a single docs page, migrating from one platform to another, or generating a sitemap from a multi-file repo. If every heading lives in its own file forever, you can usually ignore it.
- The tool uses the same slug algorithm as the rest of the site: lowercase, strip non-word characters, collapse whitespace into hyphens. This matches GitHub's renderer closely enough that the results map cleanly when published.
- Yes. Click 'Add document' to add another panel; click the trash icon on any panel to remove it. There's no hard cap — the simulator runs in real time even with dozens of documents.
- Three options: (1) rename one of the conflicting headings to be more specific (`## Setup` becomes `## Setup (API)`); (2) prefix the merged content with file-specific anchor IDs; (3) place each document under a unique sub-route on your site so the slug namespaces are separate.
- No. The slug algorithm and the collision check both run inside your browser. We never upload, log, or store any document contents.