A fast, local-first markdown editor with live preview, autosave, and GitHub-flavored markdown support.
- Overview
- Features
- Tech Stack
- Quick Start
- App Behavior
- Keyboard Shortcuts
- Export Options
- Deployment
- Privacy & Security
- Contributing
- Version History
- License
MarkdownMate is a single-user, local-first markdown editor designed for speed and simplicity. All documents are stored in browser IndexedDB — no accounts, no external APIs, no data leaves your device.
The editor provides a VSCode-like writing experience powered by Monaco Editor, with real-time GitHub-flavored markdown preview, KaTeX math rendering, and syntax-highlighted code blocks.
- Live Preview — Split view with real-time markdown rendering (editor-only, split, and preview-only modes)
- Monaco Editor — VSCode-like editing with syntax highlighting, configurable font size, and word wrap
- GitHub Flavored Markdown — Tables, task lists, strikethrough, and fenced code blocks via remark-gfm
- Math Support — KaTeX rendering for inline (
$...$) and block ($$...$$) math expressions - Autosave — Automatic saving to IndexedDB with 500ms debounce
- Document Management — Create, rename, duplicate, soft-delete, and search across documents
- Multiple Export Formats — Export to
.md, self-contained.html, or print to PDF - Light/Dark Theme — Toggle between light and dark modes
- Status Bar — Word count, character count, cursor position, and last-saved timestamp
- Keyboard Shortcuts — Save, export, and help accessible via keyboard
- About Modal — App info, version, resource links, and shortcuts reference
- Resizable Panels — Drag the split-view divider to adjust editor/preview proportions
Frontend:
- React 18 with TypeScript
- Vite 7 (dev server and production bundler)
- Tailwind CSS 3 with shadcn/ui components
- Monaco Editor (ESM bundle with local workers — no CDN)
- Zustand (state management)
- IndexedDB via
idb(document persistence) - wouter (client-side routing)
Markdown Processing:
- unified / remark-parse (markdown parsing)
- remark-gfm (GitHub Flavored Markdown)
- remark-math + rehype-katex (math rendering)
- rehype-prism-plus (syntax highlighting)
- rehype-sanitize (XSS protection)
Server:
- Express (static file serving in production, Vite proxy in development)
- helmet (strict Content Security Policy and security headers)
- winston (structured logging)
- Node.js 18+ and npm
git clone https://github.com/hexawulf/MarkdownMate.git
cd MarkdownMate
npm installnpm run devOpens at http://localhost:5004. Vite handles hot module replacement.
npm run build
npm startBuilds the client with Vite and bundles the server with esbuild. The production server serves static files from dist/.
| Script | Description |
|---|---|
npm run dev |
Start development server (Vite + Express) |
npm run build |
Build client and server for production |
npm start |
Run production server (dist/index.js) |
npm run check |
TypeScript type-checking (tsc) |
npm run typecheck |
TypeScript type-checking (tsc --noEmit) |
On first load, MarkdownMate opens IndexedDB and loads existing documents. If no documents exist, a single "Untitled Document" is created automatically. The app waits for IndexedDB to finish loading before rendering the editor, preventing duplicate document creation on startup.
All documents are stored in browser IndexedDB under the database markdownmate-db. There is no server-side storage — the Express server only serves static files and provides a /api/health endpoint.
Documents support:
- Title, content, tags, timestamps (created/updated)
- Soft-delete with restore capability
- Duplicate with "(Copy)" suffix
Content changes trigger an autosave after 500ms of inactivity. The status bar shows the last-saved timestamp and an "Unsaved" indicator when changes are pending. Manual save is available via Ctrl+S.
The editor supports three view modes, toggled via the toolbar:
- Editor — Full-width Monaco editor
- Split — Side-by-side editor and preview with a draggable divider
- Preview — Full-width rendered markdown
| Shortcut | Action |
|---|---|
Ctrl/Cmd + S |
Save document |
Ctrl/Cmd + E |
Export as Markdown |
Ctrl/Cmd + / |
Open keyboard shortcuts dialog |
Exports raw markdown content as a downloadable .md file.
Exports a single HTML file with inlined CSS, rendered markdown, KaTeX math, and syntax-highlighted code blocks. Ready to share or archive.
Opens the browser print dialog. The app includes a print stylesheet optimized for clean page layout and proper breaks.
MarkdownMate is designed for self-hosting. Build and run with PM2:
npm run build
pm2 start ecosystem.config.cjs
pm2 save
pm2 startupThe included ecosystem.config.cjs runs the production server on port 5004.
Example configuration for nginx:
server {
listen 443 ssl http2;
server_name markdown.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/markdown.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/markdown.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:5004;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
proxy_pass http://127.0.0.1:5004;
expires 1y;
add_header Cache-Control "public, immutable";
}
}sudo certbot --nginx -d markdown.yourdomain.com- 100% client-side — All documents stored in browser IndexedDB
- No server uploads — Markdown content never leaves your device
- No accounts — No authentication, no tracking, no cookies
- No analytics — No external API calls or data collection
- HTML sanitization via
rehype-sanitize(XSS protection) - Strict CSP headers — Content Security Policy via helmet.js blocks remote scripts, eval, and external connections
- No CDN dependencies — All code, fonts, and Monaco workers bundled locally
- No
eval()— No dynamic code execution anywhere in the codebase - Data URL images — Pasted/dropped images embedded as data URLs (no external requests)
Contributions are welcome. See CONTRIBUTING.md for setup instructions, code standards, and commit message conventions.
npm run check # TypeScript validation
npm run build # Build verificationSee CHANGELOG.md for the full release history.
| Version | Date | Highlights |
|---|---|---|
| 3.0.0 | 2026-03-15 | GitHub-minimal theme, startup race condition fix, Monaco bundle optimization, codebase hardening |
| 2.0.0 | 2025-11-02 | Local-first rewrite — IndexedDB storage, Monaco editor, split view, autosave, export |
| 1.0.0 | 2024-12-06 | Initial release — collaborative editing with Firebase |
MIT License — see LICENSE for details.
Made with care for markdown lovers