Markdown Broken Link Checker: 4 Ways to Find Dead Links in a Folder of .md Files
Find broken links in a folder of Markdown files with lychee, markdown-link-check, VS Code or a visual app. Tested on a real 49-file folder: 5 dead links.
On this page · 10 sections
- The short answer
- What counts as a broken link in Markdown?
- What we tested, on a real folder
- 1. lychee: the fastest command-line checker
- 2. markdown-link-check: the npm option
- 3. VS Code: flag broken links while you edit
- 4. Markdown Everywhere: see every broken link on a map
- How do I stop Markdown links from breaking?
- Which Markdown link checker should you use?
- Frequently asked questions
Markdown links do not warn you when they break. You move a folder, rename a file or change a heading, and every link that pointed at the old path quietly turns into a dead end. Nobody notices until a reader, a teammate or an AI agent follows it and gets nothing.
A Markdown broken link checker finds those dead ends before anyone else does. We tested four ways to do it on a real folder of notes on a Mac, and found out that the most popular command-line tool misses a whole kind of link.
The short answer#
Run lychee with lychee --offline '**/*.md' to find links to missing files in seconds. Add --include-fragments to check heading anchors. lychee and VS Code ignore [[wikilinks]], so for Obsidian-style notes use Obsidian or Markdown Everywhere.
What counts as a broken link in Markdown?#
There are four kinds, and no single tool catches all of them:
- Missing file.
[setup](docs/setup.md)wheredocs/setup.mdno longer exists. This is the most common one by far. - Missing heading.
[install](guide.md#install)where the file exists but the## Installheading was renamed. - Missing wikilink target.
[[Meeting notes]]in Obsidian-style notes, where no file calledMeeting notes.mdexists. - Dead web URL.
[docs](https://example.com/old-page)that now returns 404.
Local links (the first three) can be checked instantly and offline. Web URLs need network requests, are slow, and fail for reasons that have nothing to do with you (rate limits, bot blocking), so we check those separately or not at all.
What we tested, on a real folder#
Tested on a MacBook Pro 14" (M1 Pro, 16 GB), macOS 26.3, October 19, 2026.
We used two folders:
- A real one: 49 research notes from our own studio, written over three weeks. They contain 906 links in total, most of them web URLs, and 37 local links between files.
- A small trap folder: three files we built with one link of each local kind: a missing file, a missing heading, a missing
[[wikilink]], plus links that work.
The real folder had 5 broken local links. All five came from the same cause: we had moved a group of project folders from one directory to another, and older notes still pointed at the old location. Nothing was misspelled. That is how links usually die.
| Checker | Real folder (5 broken) | Missing file | Missing heading | Missing [[wikilink]] |
Time on 49 files |
|---|---|---|---|---|---|
lychee 0.24.2 --offline |
5 of 5 | ✅ | only with --include-fragments |
❌ ignored | 0.04 s |
| A 30-line Python script | 5 of 5 + 2 false alarms | ✅ | ❌ | ✅ | 0.04 s |
| Markdown Everywhere (by its link parser) | — not timed | ✅ | ❌ | ✅ | updates live |
The Python script's two false alarms were the words [[link]] and [text](link) written as examples inside a note about Markdown syntax. Any checker that reads raw text has this problem; lychee skipped them because it does not parse wikilinks at all and treated link as not a URL. Keep that in mind before you "fix" a link that was only an example.
1. lychee: the fastest command-line checker#
lychee is a free, open-source link checker written in Rust, with about 4,000 stars on GitHub as of October 2026. It reads Markdown, HTML and plain text, and checks both local files and web URLs.
Install it on a Mac with Homebrew:
brew install lychee
Check only local links (fast, no network):
lychee --offline '**/*.md'
Also check that heading anchors exist:
lychee --offline --include-fragments '**/*.md'
Check web URLs too (slower; can hit rate limits):
lychee '**/*.md'
On our real folder, the offline run checked 906 links in 20 milliseconds and printed each broken link with its file, line and column, such as (at 4:5). In the trap folder, it caught the missing file, caught the missing heading only with --include-fragments, and ignored the broken [[wikilink]] completely. If your notes come from Obsidian, Foam or Logseq, lychee alone will tell you everything is fine when it is not.
Use lychee when: your docs use standard [text](path.md) links, such as a project's docs/ folder or a README set, and you want a check you can run in CI.
2. markdown-link-check: the npm option#
markdown-link-check is the older, Node.js-based option, at version 3.15.0 (July 28, 2026). If your project already uses npm, it fits in without another install:
npx markdown-link-check README.md
find . -name "*.md" -not -path "./node_modules/*" -exec npx markdown-link-check -q {} \;
It checks one file per run, so the find line loops over a folder. It supports a JSON config to ignore patterns (for example, localhost URLs) and is common in GitHub Actions. Because it starts once per file and checks web URLs by default, it takes longer than lychee on big folders. Like lychee, it does not understand wikilinks.
A third tool in the same family is remark-validate-links, which checks local links and headings as part of a remark pipeline. It is a good pick if you already lint Markdown with remark.
3. VS Code: flag broken links while you edit#
If you write Markdown in VS Code, you already have a checker. It is off by default. Turn it on in Settings by searching for markdown.validate.enabled, or add this to settings.json:
"markdown.validate.enabled": true
VS Code then underlines links to missing files and missing headings in your workspace and lists them in the Problems panel. It also has an option to update links when you rename or move a file, markdown.updateLinksOnFileMove.enabled, which prevents most breakage in the first place. Both are documented in Markdown and Visual Studio Code.
The limits: it only checks local links, it does not read [[wikilinks]], and it shows problems file by file rather than a summary of the whole folder.
4. Markdown Everywhere: see every broken link on a map#
We built Markdown Everywhere, a free app for Mac and Windows, for a different job: understanding a folder full of .md files, such as docs, research notes or AI agent skills. Broken links fall out of that naturally.
Add a folder and the app reads every Markdown file in it. It understands both [text](file.md) and [[wiki]] links. Then:
- A Broken links tab lists only the files that contain a dead link.
- In the Table view, each file with broken links shows a ⚠ badge with the count; hover it to see which targets are missing.
- The reader shows a "Broken links" section under each file, next to its links in and out.
- The map draws files as cards with dashed arrows for links, and an orange dot on files nothing links to.
Its link parser treats [[Missing note]] as broken when no such file exists, the exact case lychee ignored, and the app's own test suite checks that case. Links inside fenced code blocks are skipped, so syntax examples there do not raise false alarms. It does not check web URLs or heading anchors, so it is not a CI tool; pair it with lychee for that. Markdown Everywhere Pro ($9.99 once) can also rename a file and update the links to it in other files, which stops this kind of breakage at the source. See the Markdown Everywhere page.
How do I stop Markdown links from breaking?#
Finding broken links is the cleanup. These habits reduce how often you need it:
- Rename and move files with a tool that updates links. VS Code (
markdown.updateLinksOnFileMove.enabled), Obsidian and Markdown Everywhere Pro all can. Finder andmvcannot. - Link to files, not headings, when you can. Headings change more often than file names.
- Use relative paths.
../guide.mdsurvives when you move the whole folder;/Users/you/notes/guide.mddoes not. - Run
lychee --offlinebefore you commit, or add it to CI so a broken docs link fails the build. - Check after big moves. Every time we reorganized folders, broken links appeared within the same day.
If AI agents read your docs (Claude Code skills, CLAUDE.md files, plans), broken links matter more: an agent that follows a dead link either stops or guesses. Our guide to CLAUDE.md best practices covers how to keep those files readable.
Which Markdown link checker should you use?#
- Docs in a code repo, standard links, CI: lychee with
--offline --include-fragments. - Already on npm and GitHub Actions: markdown-link-check.
- You write in VS Code: turn on
markdown.validate.enabledand link updates on move. - Obsidian-style notes with
[[wikilinks]], or you want to see the whole folder: Markdown Everywhere or Obsidian itself.
For reading and browsing big Markdown folders, see our list of the best Markdown viewers for Mac and how to read the Markdown that Claude Code writes.
Frequently asked questions
How do I check for broken links in Markdown files?
Run a link checker over the folder. lychee is the fastest: install it with Homebrew and run lychee --offline '**/*.md' to check only local links. markdown-link-check does the same through npm, VS Code can flag broken links while you edit, and Markdown Everywhere lists every file with a broken link in one tab.
Does lychee check wikilinks?
No. In our test, lychee 0.24.2 ignored [[Missing note]], a wikilink to a file that did not exist, while it caught a broken [text](file.md) link in the same file. If your notes use Obsidian-style [[wikilinks]], use Obsidian, Markdown Everywhere or a custom script.
How do I find broken links in Obsidian?
Obsidian treats a wikilink to a note that does not exist as an unresolved link and shows it in a fainter style. Clicking it creates the note. In the graph view, turn off the Existing files only filter to see unresolved links as their own nodes.
Can VS Code find broken links in Markdown?
Yes. Turn on the setting markdown.validate.enabled and VS Code marks links to missing files and missing headings in your workspace as problems. It checks local links only, not web URLs, and you see results per file in the Problems panel.
Why do Markdown links break?
Mostly because files move. Renaming a file, moving a folder or changing a heading breaks every link that pointed at the old path. In our test all five broken links came from one folder being moved; nothing was misspelled.

