Skip to content

Manan-Santoki/Binderly

Repository files navigation

Binderly

Markdown rendered like GitHub. Exported like print.

An open-source Markdown workbench: live preview, page-perfect PDF export, Mermaid diagrams in the PDF, GitHub-accurate themes, and shareable view-only links. No size caps. No watermarks.

🌐 Live demo: https://binderly.msantoki.com/

Cap.2026-04-27.at.17.17.31.mp4

Features

  • GitHub-accurate themes β€” light + dark variants powered by the official github-markdown-css Primer stylesheet. Your rendered Markdown matches github.com.
  • Mermaid diagrams in the PDF β€” sequence, flowchart, gantt, class, state. Rendered server-side via Puppeteer so they survive the trip into the export. Theme auto-pairs with the document theme.
  • GitHub Flavored Markdown β€” alerts (> [!NOTE], [!WARNING], [!CAUTION], etc.), footnotes, task lists, tables with column alignment.
  • Auto table of contents + heading anchors using github-slugger for slug parity with GitHub itself.
  • Page-perfect PDFs β€” A4, page numbers in footer, break-inside: avoid on code blocks, tables, alerts, and Mermaid SVGs so nothing splits awkwardly. Optional rounded-card or full-bleed mode.
  • Shareable view-only links β€” click Share, get a public URL like /v/<uuid>. Backed by Postgres. Each click is an immutable snapshot.
  • Custom CSS injection for brand-matching, plus four curated typographic themes (GitHub Light/Dark, Editorial Serif, Modern Neutral, Midnight Focus).
  • Privacy-first β€” self-hosted instances ship noindex by default. Opt-in to indexing and analytics via env vars.
  • Self-hostable β€” Next.js + Puppeteer + Postgres. MIT-licensed.

Quick start

Prerequisites

  • Node.js 22+
  • pnpm 9.15.2+
  • Postgres 14+ (only required for the share-link feature; the editor + PDF export work without it)
  • Docker (optional, for the easiest Postgres setup)

Install

git clone https://github.com/Manan-Santoki/Binderly
cd Binderly
pnpm install

pnpm install downloads a Chromium binary for Puppeteer (~170 MB on first install).

Database (only if you want the Share button)

docker run -d --name binderly-pg \
  -p 5432:5432 \
  -e POSTGRES_USER=binderly \
  -e POSTGRES_PASSWORD=devpw \
  -e POSTGRES_DB=binderly \
  postgres:16-alpine

cat > .env.local <<'EOF'
DATABASE_URL=postgres://binderly:devpw@127.0.0.1:5432/binderly
DATABASE_SSL=false
EOF

pnpm db:migrate

Run

pnpm dev          # development (turbopack, hot reload)
# or
pnpm build && pnpm start   # production

Open http://localhost:3000.

Configuration

All env vars are optional (except DATABASE_URL if you use sharing). See .env.example for the canonical list.

Variable Required for Notes
DATABASE_URL Share links Postgres connection string
DATABASE_SSL β€” false (self-hosted), require (managed providers), default prefer
NEXT_PUBLIC_SITE_URL SEO on hosted instance Set to your canonical URL to enable indexing, sitemap, canonical tag, JSON-LD. Leave unset for private/internal deploys β€” the app ships noindex by default.
NEXT_PUBLIC_ANALYTICS_SRC Analytics Script URL for a privacy-friendly analytics provider (Plausible/Umami-style). Both vars must be set; otherwise zero tracking JS loads.
NEXT_PUBLIC_ANALYTICS_SITE_ID Analytics Site identifier passed via data-site-id

NEXT_PUBLIC_* vars are inlined at build time. Changes require a rebuild, not just a restart.

How it works

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Workbench (UI)  │────▢│  /api/pdf       │────▢│  Puppeteer   β”‚
β”‚  react-markdown  β”‚     β”‚  marked +       β”‚     β”‚  β†’ A4 PDF    β”‚
β”‚  remark-gfm      β”‚     β”‚  marked-alert + β”‚     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚  remark-alert    β”‚     β”‚  mermaid UMD    β”‚
β”‚  rehype-slug     β”‚     β”‚  injection      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β”‚ Share button
        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  /api/share      │────▢│  Postgres       β”‚
β”‚  (POST snapshot) β”‚     β”‚  shared_docs    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β”‚ /v/[id]  (public read-only viewer)
        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  SharedDocViewer β”‚
β”‚  (same renderer  β”‚
β”‚  as workbench)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Two markdown libraries are used deliberately:

  • react-markdown in the live preview β€” lots of plugins, runs in the browser, fast.
  • marked in the PDF render path β€” server-friendly, easier to swap renderers, integrates cleanly with Puppeteer.

GFM alert plugins are paired across the two (remark-github-blockquote-alert for the preview, marked-alert for the PDF) so both emit the same markdown-alert markdown-alert-{variant} classes β€” one stylesheet covers both.

Project layout

src/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ api/pdf/route.ts          # POST: render markdown -> PDF
β”‚   β”œβ”€β”€ api/share/route.ts        # POST: persist snapshot, return UUID
β”‚   β”œβ”€β”€ v/[id]/page.tsx           # public read-only viewer
β”‚   β”œβ”€β”€ layout.tsx                # metadata + JSON-LD
β”‚   β”œβ”€β”€ page.tsx                  # home β€” workbench + SEO landing
β”‚   β”œβ”€β”€ robots.ts                 # gated on NEXT_PUBLIC_SITE_URL
β”‚   └── sitemap.ts                # gated on NEXT_PUBLIC_SITE_URL
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ pdf-workbench/            # editor, mermaid, code-block, toc
β”‚   β”œβ”€β”€ shared-doc-viewer.tsx     # used by /v/[id]
β”‚   β”œβ”€β”€ seo-landing.tsx           # SSR feature/FAQ block
β”‚   └── ui/                       # Radix-based primitives
└── lib/
    β”œβ”€β”€ pdf.ts                    # marked + Puppeteer pipeline
    β”œβ”€β”€ themes.ts                 # theme registry + helpers
    β”œβ”€β”€ db.ts                     # Postgres queries
    β”œβ”€β”€ seo.ts                    # hosted-mode toggle + constants
    β”œβ”€β”€ github-markdown-themes/   # bundled Primer CSS
    └── highlight-themes/         # bundled highlight.js CSS
migrations/0001_shared_documents.sql
scripts/migrate.ts

Customization

Add a theme

See src/lib/themes.ts. Existing themes are CSS-variable based and live in themeTokens. The Primer-based themes (github-light, github-dark) wrap the content in <div class="markdown-body">; the rest use <div class="md-theme">. Adding a new CSS-variable theme is a few lines β€” see CONTRIBUTING.md.

Modify PDF styles

src/lib/pdf.ts is the server-side render path. Page break controls, the page-numbered footer template, and theme-aware CSS overrides all live there.

Hosting

Standard Next.js hosting story β€” Node 22+, persistent Postgres, and a process supervisor of your choice. The PDF route uses Puppeteer's bundled Chromium and works in containers with --no-sandbox (already configured).

For SEO on your hosted instance, set NEXT_PUBLIC_SITE_URL=https://your-domain and rebuild. That switches the app into hosted mode (sitemap, canonical, indexable robots, JSON-LD with the right URL).

Roadmap

Open to suggestions. Things on my list:

  • Editable share links (currently snapshots only)
  • Math support (KaTeX/MathJax)
  • Diagram alternatives β€” PlantUML, D2, Graphviz
  • Theme builder UI

Open an issue if you want to discuss any of these or pitch your own.

Contributing

PRs welcome β€” see CONTRIBUTING.md.

License

MIT Β© 2026 Manan Santoki

About

Open-source Markdown workbench: live preview, GitHub-accurate themes, Mermaid diagrams, and page-perfect PDF export. No size caps, no watermarks.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages