CLI tool
DavidWells/markdown-magic avatar
DavidWells/markdown-magic

markdown-magic keeps generated sections of a README in sync with your code

💫  Automatically format markdown files via comment blocks using source code, external data & custom transforms.

871 stars223 forksJavaScriptLicense varies

At a glance

What is it?
markdown-magic is a Node.js tool that finds comment markers in markdown files and replaces the block between them with content pulled from source files, remote URLs, custom transforms or a template engine. It fits teams whose documentation is generated in CI, and it is the wrong tool when the prose needs a human eye on every commit.
Who is it for?
Pick markdown-magic when the parts of your documentation that repeat code, file contents or a table of contents are the parts that keep going stale, and when a CI job is allowed to commit the result. Skip it when the generated block needs editorial judgement, when a remote URL must not be contacted during a build, or when you want one file to feed several outputs.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 89 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem: documentation that repeats code and rots

Most README files carry two kinds of content. Prose explains the project. The rest repeats facts that already exist elsewhere: the install command, the option list, the API signature, the directory tree. The second kind goes stale the moment the code changes, and nobody notices because the diff looks like a documentation edit.

markdown-magic attacks that by marking the replaceable regions with HTML comments and filling them programmatically. The comment syntax is deliberately invisible in rendered output, so a reader sees a clean document while the repository holds instructions for generating it.

The project describes itself as formatting markdown files automatically via comment blocks using source code, external data and custom transforms. The list of built-in transforms includes TOC for a table of contents, CODE for source snippets, FILE for the contents of a file, REMOTE for a file fetched over HTTP, fileTree for a directory listing, and install for the installation snippet.

That is a narrow, concrete purpose: a documentation build step for one kind of file. It is not a documentation framework and it does not compete with a static site generator.

Five ways to spell the same comment marker

The syntax section offers the same idea in five notations, which exist because comment markers must not collide with content a technical writer may legitimately want to include.

The plain form names a transform and passes options as key and value pairs:

md
<!-- docs transformName optionOne='hello' optionTwo='there' -->
content to be replaced
<!-- /docs -->

The same transform can be wrapped in curly braces, in square brackets or in parentheses, which is the fastest way to keep a block from colliding with an example that already uses the plain form. A fifth form passes options as a function call, with array values in brackets:

md
<!-- docs transformName(
  foo='bar'
  baz=['qux', 'quux']
) -->
content to be replaced
<!-- /docs -->

Whether the wrappers are worth the extra variety is a fair question. The cost is that a template language now has to recognise five shapes, and a reader who edits the file has to know which one applies. The benefit is that a document which demonstrates a default comment block can still show the literal text without the tool rewriting it.

Installing npm package or the prebuilt md-magic binary

Two install paths are documented. The npm route adds the package as a development dependency:

bash
npm install markdown-magic --save-dev

The second route avoids Node.js entirely by downloading a prebuilt binary from the GitHub Releases page. Each platform has its own asset, and the file has to be made executable before it runs:

bash
# macOS (Apple Silicon)
curl -fsSL https://github.com/DavidWells/markdown-magic/releases/latest/download/md-magic-darwin-arm64 -o md-magic
chmod +x md-magic

The same pattern applies to macOS on Intel, Linux on x64 and Linux on ARM64, with the asset name changing to md-magic-darwin-x64, md-magic-linux-x64 and md-magic-linux-arm64. The binary route matters in CI images where installing a Node toolchain is more work than fetching one file.

One detail in the CLI section is easy to miss and useful to know: if a file named md.config.js or markdown.config.js exists and markdown-magic is invoked from there, that file is used as the configuration automatically, unless the --config flag points somewhere else. Most projects will keep their transform definitions in that file rather than inline.

The glob decides which files get rewritten

The command line is small. Running markdown, or its shorter alias md-magic, with no arguments processes the markdown files in the current working directory:

bash
md-magic --file '**/*.md' --config ./config.file.js

The --file flag takes a glob and the --config flag takes a path to a JavaScript configuration file. In practice teams wire the same command into an npm script so a single command regenerates the docs:

json
"scripts": {
  "docs": "md-magic --file '**/*.md'"
},

The glob is the part worth thinking about. Because the transform writes back into the same markdown files it read, a pattern that matches generated output as well as source input can feed a file back into itself on the next run. The pattern '**/*.md' reaches every markdown file in the repository, including the ones inside node_modules unless something excludes them.

The other half of the CLI surface is the ability to run markdown --help and see the rest of the options. That help output is the only reference for flags beyond --file and --config, and the prose documentation does not enumerate the rest.

Programmatic use hands back a result object per file

The library form takes either a path or a glob, and the README shows it resolving to a promise of results:

js
import path from 'path'
import markdownMagic from 'markdown-magic'

// Process a Single File
const markdownPath = path.join(__dirname, 'README.md')
markdownMagic(markdownPath)

The CommonJS variant destructures the function from the source directory and processes every markdown file in the current working directory by default, logging the result keys:

js
const { markdownMagic } = require('../src')

/* By default all .md files in cwd will be processed */
markdownMagic().then((results) => {
  console.log('result keys', Object.keys(results))
})

The API section documents the entry point as markdownMagic(globOrOpts, options), where the first argument is either files to process or a configuration object and the second is an optional MarkdownMagicOptions. The documented result type is MarkdownMagicResult.

The option names beyond that are only partly visible in the visible documentation, so treat the published type definitions as the reference for the full surface. The README also lists MarkdownMagicOptions and OutputConfig among the exported types.

Generating docs inside a GitHub Actions workflow

The workflow example the project publishes is the reason many teams meet this tool. It downloads the Linux binary, runs it over every markdown file, and commits the result back to the branch on a push that touches markdown or source:

yaml
name: Update Markdown

on:
  push:
    paths:
      - '**.md'
      - 'src/**'

jobs:
  update-docs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Download md-magic
        run: |
          curl -fsSL https://github.com/DavidWells/markdown-magic/releases/latest/download/md-magic-linux-x64 -o md-magic
          chmod +x md-magic

      - name: Run markdown-magic
        run: ./md-magic --files '**/*.md'

      - name: Commit changes
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add -A
          git diff --staged --quiet || git commit -m "docs: update markdown"
          git push

Note that the workflow uses --files with an s while the prose section uses --file. The exact spelling accepted by the CLI is worth checking against markdown --help in your own repository before you copy the file, since a wrong flag name in CI fails quietly at the step that regenerates the docs.

Two other projects are listed as alternatives in the same section: markdown-code-inject for injecting code snippets, and markdown-autodocs for generating documentation from code. The difference is narrow. markdown-magic covers a wider set of transform kinds, including remote files and templates, while the alternatives concentrate on the code snippet case.

Custom transforms, plugins and the older plugin versions

Built-in transforms cover the common cases, and the project also documents writing your own, plus a plugin mechanism with a plugin example. The examples directory in the repository holds the zero-config example, a basic usage example, an options example, a readme generation example and a plugin example.

Plugins are where the version history shows. The documentation carries a section titled Legacy v1 and v2 plugins next to the current plugin documentation, which tells you the plugin interface changed between major versions. If you are integrating an existing plugin, check which interface it targets before copying the snippet, because the old form is still documented but is no longer the primary path.

The same section also lists misc markdown helpers and prior art, the latter pointing at other tools in the same space so you can compare approaches.

Because plugins run as code inside your build, the trust boundary is your own configuration file: a plugin that fetches a URL during generation makes your documentation step depend on the network, and the documentation does not promise caching or offline behaviour.

A monorepo with pnpm and lerna releases

The repository is a workspace, not a single package. The root package.json is named markdown-magic-monorepo, is marked private, and declares [email protected] as the package manager with a pnpm engine requirement of at least 10.0.0. The packages directory holds the published packages, and lerna handles version bumps through a next-version script that runs lerna version with --no-push and --no-git-tag-version.

The published package is distributed as markdown-magic with the binary named md-magic. Recent releases came in quick succession: version 4.11.0 was published on 2026-06-29, 4.10.5 on 2026-06-27 and 4.10.4 on 2026-06-23. The last push to the default branch was on 2026-07-27, and the repository is not archived.

On the licence, the GitHub listing for the repository shows no licence identifier, while the root package.json declares MIT. That difference is worth resolving in your own project before shipping: the file that governs what you may redistribute is the licence in the repository, not the field in a package manifest of the tool you depend on.

Editorial conclusion

Pick markdown-magic when the parts of your documentation that repeat code, file contents or a table of contents are the parts that keep going stale, and when a CI job is allowed to commit the result. Skip it when the generated block needs editorial judgement, when a remote URL must not be contacted during a build, or when you want one file to feed several outputs. Before you adopt it, run md-magic --file '**/*.md' against one repository, diff the result, and confirm that the file you mark with a MD-MAGIC-EXAMPLE comment is the one your team actually edits, because the project's own README is generated the same way.

Frequently asked questions

How do I install markdown-magic?

Add it as a development dependency with npm install markdown-magic --save-dev, or download a prebuilt binary named md-magic for your platform from the GitHub Releases page and make it executable with chmod +x. The binary route avoids needing Node.js on the machine that runs it.

How do I keep a README section in sync with a file in my repository?

Mark the section with a comment block and let the FILE transform pull the file in, or the REMOTE transform for a file fetched over HTTP. The same mechanism covers source snippets with the CODE transform, a directory listing with fileTree and a table of contents with TOC.

Can markdown-magic regenerate documentation in CI?

Yes. The published GitHub Actions example downloads the md-magic-linux-x64 binary, runs it over the markdown files and commits the result back to the branch on a push that touches markdown or source files.

How do I write my own transform for markdown-magic?

The documentation has a section on adding custom transforms and a section on plugins, with a plugin example among the files in the examples directory. Plugins run as code inside your own build, so anything they fetch becomes a dependency of your documentation step.

Official sources

  1. DavidWells/markdown-magic on GitHub
  2. Issues
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/davidwells-markdown-magic.svg)](https://hysenlabs.com/projects/davidwells-markdown-magic)

Was this useful?