npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@inkless/mdbrowse

v0.2.5

Published

Browse a folder of Markdown locally as a GitHub-styled site. Sidebar nav, ⌘K file search, live reload, mermaid + math, shiki dual-theme highlighting, programmatic API — fully offline, no GitHub API calls.

Readme

mdbrowse

Browse a folder of Markdown locally as a GitHub-styled site. No GitHub API calls — everything renders in-process.

What you get out of the box:

  • a file-tree sidebar that scans the served directory and highlights the current file
  • a ⌘K / Ctrl+K file picker with fzf-style subsequence matching across filenames + folders
  • websocket live reload across the whole tree on save (not just the open file)
  • synthetic directory listings when a folder has no README.md, so URLs never dead-end on a 404
  • GitHub-flavored alerts (> [!NOTE], > [!TIP], > [!IMPORTANT], > [!WARNING], > [!CAUTION]) with the real octicon SVGs
  • dual-theme syntax highlighting via shiki — one render serves both github-light and github-dark, swaps via CSS variables
  • client-side Mermaid + MathJax (inline $x$, block $$x$$, fenced ```math)
  • a typed programmatic APIrenderMarkdown, renderMarkdownWithHighlighting, serveMarkdown — for embedding inside a Node service
  • ships as an npm package: npx, pnpm dlx, or global install — no Go/Python toolchain required

Install

# global
pnpm add -g @inkless/mdbrowse
npm  i  -g @inkless/mdbrowse
yarn global add @inkless/mdbrowse

# one-shot, no install
pnpm dlx @inkless/mdbrowse
npx       @inkless/mdbrowse
yarn dlx  @inkless/mdbrowse   # yarn 2+ (Berry)

The npm package is published as @inkless/mdbrowse; the binary it installs on your PATH is mdbrowse.

Usage

mdbrowse always serves the current directory as a browsable site (sidebar lists every .md file under it; Cmd+K searches across the whole tree). The optional positional argument is just which page to land on first — pass nothing and you land on ./README.md if it exists, otherwise on a synthetic directory listing.

mdbrowse                       # serve cwd; land on ./README.md if present
mdbrowse docs/guide.md         # serve cwd; land on /docs/guide.md
mdbrowse docs/                 # serve cwd; land on /docs/ (its README or listing)
mdbrowse -p 3000               # custom port (falls back to next free if busy)
mdbrowse --no-browser          # don't auto-open the browser
mdbrowse --no-reload           # disable live reload on file changes
mdbrowse -H 0.0.0.0            # bind to all interfaces (LAN access)
mdbrowse --all                 # also include dotfiles + node_modules / dist / …
mdbrowse --code                # also list source files (.ts / .py / .go / …) in the sidebar

The default URL is http://localhost:6419/. Hit Ctrl-C to stop.

To serve a different directory, cd into it first — mdbrowse always treats the current working directory as the root of the site.

CLI reference

mdbrowse [options] [file]

Arguments:
  file                  Page to land on first (defaults to README.md in the
                        current directory if present). The whole directory is
                        always served — this argument is just the initial URL.

Options:
  -v, --version         Print version and exit
  -b, --browser         Open in browser on start (default)
      --no-browser      Do not open the browser
  -H, --host <host>     Host to bind (default: localhost)
  -p, --port <port>     Port to bind; falls back to the next free port if busy (default: 6419)
      --bounding-box    Wrap content in GitHub bounding box (default)
      --no-bounding-box Disable bounding box
      --no-reload       Disable browser auto-reload on file changes
      --all             Show every directory in the sidebar + ⌘K search,
                        including dotfiles and node_modules / dist / etc.
                        (off by default)
      --code            Also list recognized source files (.ts / .py / .go /
                        .json / Dockerfile / …) in the sidebar + ⌘K search.
                        Code files are always rendered when navigated to
                        directly — this flag only controls sidebar listing.
                        (off by default)
  -h, --help            Display help

Features

  • 📄 GitHub-styled rendering — heading anchors, GFM tables, strikethrough, autolinking, footnotes, task lists
  • 🎨 Syntax highlighting via shiki with built-in github-light and github-dark themes (dual-theme via CSS variables, swaps on theme toggle)
  • 🧾 Browse source files too — navigate to .ts, .py, .go, .json, .yaml, Dockerfile, etc. and they render in the same chrome with shiki highlighting. Unrecognized text files render as plaintext in the layout; binary files stream raw; .html / .svg keep rendering natively. Pass --code to also list source files in the sidebar + ⌘K search.
  • 📦 GitHub-flavored alerts> [!NOTE], > [!TIP], > [!IMPORTANT], > [!WARNING], > [!CAUTION]
  • 🔗 Issue/PR references#123 (auto-linked when run inside a GitHub repo) and owner/repo#123
  • 🧩 Mermaid diagrams rendered client-side
  • Math via MathJax (inline $x$, block $$x$$, fenced ```math)
  • 🖼️ <details> state preserved across reloads (sessionStorage)
  • 🌗 Light/dark theme toggle with system-preference detection
  • 📁 File-tree sidebar — automatically built from the served directory, current file highlighted
  • 🔍 File searchCmd+K / Ctrl+K opens a fzf-style picker that matches filenames and folder names; arrow keys + Enter to jump
  • 🔄 Live reload over websocket on file changes (disable with --no-reload)
  • 😀 GitHub emoji shortcodes (:ship: → 🚢)
  • 🚫 No external API calls — works fully offline

Programmatic API

mdbrowse is also a library:

import { renderMarkdown, renderMarkdownWithHighlighting, serveMarkdown } from "@inkless/mdbrowse";

// Sync render, no syntax highlighting (fastest):
const { html, title } = renderMarkdown("# hello\n");

// Async render with shiki syntax highlighting:
const { html: html2 } = await renderMarkdownWithHighlighting("```js\nconst x=1\n```\n");

// Spin up the local server programmatically:
const handle = await serveMarkdown("README.md", {
  host: "localhost",
  port: 3000,
  browser: false,
});
console.log(handle.url);
await handle.close();

For repeated rendering (e.g. inside a long-running server), build the renderer once:

import { createRendererWithHighlighting, render } from "@inkless/mdbrowse";
const md = await createRendererWithHighlighting();
for (const doc of docs) {
  const { html } = render(md, doc);
  // …
}

Repository auto-detection

Bare #NNN references (without an owner/repo prefix) only resolve to GitHub URLs when a repository is configured. The CLI auto-detects via git remote get-url origin in the served directory. To override programmatically:

renderMarkdown(md, { repository: "octocat/hello-world" });

Heritage

mdbrowse started as a Node.js port of go-grip (itself a Go port of grip). It has since grown beyond the original "preview a single README" framing into a folder browser: sidebar nav across the tree, ⌘K search, synthetic directory listings, and a programmatic API for embedding the renderer/server in your own Node code.

Development

git clone [email protected]:inkless/mdbrowse.git
cd mdbrowse
pnpm install

pnpm dev          # tsup watch
pnpm test         # vitest
pnpm lint         # biome
pnpm typecheck    # tsc --noEmit
pnpm build        # one-shot build to dist/
node dist/cli.js README.md

Releases

Versioning + changelog are automated by Release Please. Commit to main using Conventional Commits (feat: …, fix: …, docs: …, chore: …); the action keeps a single open "Release PR" that bumps package.json and updates CHANGELOG.md. Merging the Release PR cuts the vX.Y.Z tag, which triggers release.yml to publish to npm via Trusted Publishing OIDC.

License

MIT © Guangda Zhang