CodiMD / HedgeDoc
Real-time collaborative markdown editing — deployment, features, authentication & operations
Overview
CodiMD (now renamed HedgeDoc) is an open-source, self-hosted platform for real-time collaborative markdown editing. It allows multiple users to simultaneously edit a single markdown document in the browser, seeing each other's changes instantly via WebSocket connections.
HedgeDoc is the community-driven successor to CodiMD, which itself was a fork of the open-source edition of HackMD. The naming history is confusing: HackMD → CodiMD (open-source fork) → HedgeDoc (community rename in 2020). The commercial HackMD product continues as a separate SaaS offering, while HedgeDoc is the fully open-source, self-hosted alternative.
Why self-host collaborative markdown?
- Data sovereignty — Sensitive meeting notes, runbooks, and documentation stay on your infrastructure, not on third-party SaaS
- Real-time collaboration — Google Docs-like experience but for markdown, with syntax highlighting, live preview, and no vendor lock-in
- Developer-friendly — Native support for code blocks, Mermaid diagrams, LaTeX math, slide decks, and other markdown extensions
- Lightweight — A single Node.js process with a database is all you need. Minimal infrastructure compared to a full wiki or CMS
- Integration — Supports LDAP, OAuth2, SAML for enterprise SSO. Export to PDF, HTML, or GitHub Gist
Throughout this guide, "CodiMD" and "HedgeDoc" are used interchangeably. The Docker image is quay.io/hedgedoc/hedgedoc and the project repository is github.com/hedgedoc/hedgedoc. If you see references to codimd in older documentation or config files, it refers to the same software.
Architecture
HedgeDoc 1.x is a Node.js application built on Express.js. The architecture is straightforward: a single application process handles HTTP requests, serves the web UI, manages WebSocket connections for real-time collaboration, and communicates with a database for persistence.
Core components
Node.js Application
Single process running Express.js. Handles HTTP routes, WebSocket connections (via Socket.IO), markdown rendering, and authentication. Stateless beyond database and file storage.
Database
Stores notes, user accounts, revision history, and session data. Supports PostgreSQL (recommended for production), MySQL/MariaDB, and SQLite (single-user/dev only).
File Storage
Uploaded images and attachments are stored on the local filesystem (default), S3-compatible storage (AWS S3, MinIO), Azure Blob Storage, or Imgur. Local storage is the default.
Reverse Proxy
Nginx, Caddy, or similar. Required for TLS termination and WebSocket proxying. Must be configured to pass Upgrade and Connection headers for WebSocket support.
For production, always use PostgreSQL as the database backend. SQLite does not handle concurrent writes well and will cause issues under multi-user load. MySQL works but PostgreSQL has better JSON support and is the best-tested backend for HedgeDoc.
Deployment
HedgeDoc can be deployed via Docker (recommended), manual Node.js installation, or on Kubernetes. Configuration is done through environment variables or a config.json file.
Docker deployment (recommended)
The official Docker image is the simplest way to run HedgeDoc in production. A docker-compose.yml with HedgeDoc + PostgreSQL is the most common setup:
services:
hedgedoc:
image: quay.io/hedgedoc/hedgedoc:1.10.7
environment:
- CMD_DB_URL=postgres://hedgedoc:secret@db:5432/hedgedoc
- CMD_DOMAIN=docs.example.com
- CMD_PROTOCOL_USESSL=true
- CMD_URL_ADDPORT=false
- CMD_ALLOW_ANONYMOUS=false
- CMD_DEFAULT_PERMISSION=limited
- CMD_IMAGE_UPLOAD_TYPE=filesystem
volumes:
- uploads:/hedgedoc/public/uploads
ports:
- "3000:3000"
depends_on:
- db
restart: always
db:
image: postgres:17-alpine
environment:
- POSTGRES_USER=hedgedoc
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=hedgedoc
volumes:
- db-data:/var/lib/postgresql/data
restart: always
volumes:
uploads:
db-data:
Manual Node.js install
- Requires Node.js 20+ (Node 18 support was dropped; check HedgeDoc docs for exact version compatibility)
- Clone the repository, run
yarn installandyarn build - Configure via
config.jsonor environment variables prefixed withCMD_ - Use a process manager like
systemdorpm2to keep it running
Kubernetes deployment
- Community Helm charts are available (not officially maintained)
- Key considerations: persistent volume for uploads, database as a StatefulSet or external managed database, WebSocket-aware ingress configuration
- Set
CMD_DOMAINto match the ingress hostname - If using multiple replicas, you need sticky sessions or a shared session store (Redis) since WebSocket connections are stateful
The most common deployment issue is failing to configure the reverse proxy for WebSocket connections. Nginx requires explicit proxy_set_header Upgrade $http_upgrade; and proxy_set_header Connection "upgrade"; directives. Without these, real-time collaboration will not work.
Features
HedgeDoc provides a rich collaborative editing experience with powerful markdown extensions beyond standard CommonMark.
Real-time collaboration
- Simultaneous editing — Multiple users can edit the same note at the same time. Changes appear instantly for all participants via WebSocket
- Cursor presence — See where other editors are typing in real time
- Conflict resolution — Operational Transformation (OT) handles concurrent edits without conflicts
Markdown extensions
Diagrams
- Mermaid — flowcharts, sequence diagrams, Gantt charts
- PlantUML — UML diagrams (requires external server)
- GraphViz (dot) — graph visualization
Math & Science
- LaTeX math via MathJax / KaTeX
- Inline:
$E = mc^2$ - Block:
$$\int_0^\infty f(x)dx$$
Slide Decks
- Create presentations from markdown using
---slide separators - Powered by reveal.js
- Slide mode accessible via
/slide/note-id
Code & Embeds
- Syntax highlighting for 180+ languages
- YouTube, Vimeo, Gist, Speakerdeck embeds
- ToC generation, footnotes, task lists
Revision history
Every note maintains a revision history. Users can browse previous versions and see what changed. Revisions are stored in the database and can be configured for automatic cleanup to prevent unbounded growth.
Permissions model
| Permission | Who can read | Who can edit |
|---|---|---|
| Freely | Everyone (including anonymous) | Everyone (including anonymous) |
| Editable | Everyone | Signed-in users only |
| Limited | Signed-in users only | Signed-in users only |
| Locked | Everyone | Note owner only |
| Protected | Signed-in users only | Note owner only |
| Private | Note owner only | Note owner only |
Export options
- Markdown — Download the raw
.mdfile - HTML — Rendered output as a standalone HTML file
- PDF — Print-ready export (requires browser or additional tooling)
- GitHub Gist — Publish directly to a GitHub Gist
- Reveal.js slides — Export presentations
Authentication
HedgeDoc supports a wide range of authentication backends, making it easy to integrate into existing enterprise identity infrastructure.
Supported providers
Enterprise LDAP / Active Directory
Bind to an LDAP server for user authentication. Configure via CMD_LDAP_URL, CMD_LDAP_BINDDN, CMD_LDAP_SEARCHBASE, and related environment variables. Supports TLS/STARTTLS.
Enterprise SAML 2.0
Integrate with SAML identity providers (ADFS, Okta, Keycloak). Configure via CMD_SAML_* environment variables. Supports metadata URL or manual certificate configuration.
Flexible OAuth2 / OIDC
Generic OAuth2 support plus specific integrations for GitLab, GitHub, Google, Keycloak, and Mattermost. Each has dedicated CMD_* environment variables for client ID, secret, and base URL.
Simple Local Accounts
Email + password registration. Can be enabled alongside external providers. Control registration with CMD_ALLOW_EMAIL_REGISTER. Useful as a fallback or for small teams.
Guest and anonymous access
CMD_ALLOW_ANONYMOUS=true— Allows anonymous users to create new notes without signing inCMD_ALLOW_ANONYMOUS_EDITS=true— Allows anonymous users to edit existing shared notes (if note permissions allow). Works independently ofCMD_ALLOW_ANONYMOUSCMD_ALLOW_FREEURL=true— Allows creating notes at custom URLs (e.g.,/my-meeting-notes)
In production, disable anonymous access (CMD_ALLOW_ANONYMOUS=false) and email registration (CMD_ALLOW_EMAIL_REGISTER=false) unless you have a specific need. Use LDAP or OAuth2 as the primary authentication method and set CMD_DEFAULT_PERMISSION=limited so new notes are not publicly readable by default.
Storage & Database
HedgeDoc requires a database for note content and metadata, and a storage backend for uploaded images and files.
Database options
| Database | Production Ready | Notes |
|---|---|---|
| PostgreSQL | Recommended | Best concurrency, JSON support, most tested. Use version 14+ (official examples use 17). |
| MySQL / MariaDB | Supported | Works well. Use utf8mb4 charset for full Unicode support. |
| SQLite | Dev Only | Single file, no concurrent write support. Not suitable for multi-user. |
The database connection is configured via CMD_DB_URL (connection string format) or individual CMD_DB_* environment variables for host, port, username, password, and database name.
Image and file upload storage
Default Local Filesystem
Uploads stored in /hedgedoc/public/uploads. Simple but requires persistent volume in containerized deployments. Not suitable for multi-replica setups without shared storage.
Scalable S3 / MinIO
Store uploads in S3-compatible object storage. Configure via CMD_S3_BUCKET, CMD_S3_REGION, CMD_S3_ACCESS_KEY_ID, CMD_S3_SECRET_ACCESS_KEY. Works with AWS S3, MinIO, Ceph RGW.
Azure Blob Storage
Store uploads in Azure Blob Storage. Set CMD_IMAGE_UPLOAD_TYPE=azure and configure CMD_AZURE_CONNECTION_STRING and CMD_AZURE_CONTAINER. Good option for Azure-hosted deployments.
Imgur
Upload images to Imgur's public hosting. Set CMD_IMAGE_UPLOAD_TYPE=imgur and provide CMD_IMGUR_CLIENTID. Not recommended for private or enterprise content.
CDN for Assets
Static assets (JS, CSS) can be served from a CDN by setting CMD_CDN_URL. This offloads bandwidth from the application server and improves load times for geographically distributed users.
For production deployments behind Docker or Kubernetes, use S3-compatible storage (MinIO if self-hosted) for uploads. This decouples file storage from the application container, simplifies backups, and enables multi-replica deployments.
Administration
HedgeDoc is a low-maintenance application, but production deployments require attention to backups, user management, and monitoring.
User management
- Users are created on first login via the configured authentication provider
- No built-in admin panel in HedgeDoc 1.x — user management is done via the database directly
- Set user roles by updating the
Userstable:UPDATE "Users" SET "role" = 'admin' WHERE "email" = 'admin@example.com'; - Deactivated users can be removed from the database, but their notes persist (owned by a deleted user)
Note cleanup
- Old, unused notes accumulate over time. There is no built-in auto-cleanup
- Write a periodic job to identify and archive notes not accessed in X months
- Revision history can grow large; consider pruning old revisions from the
Revisionstable
Backup strategies
Database Backup
Use pg_dump (PostgreSQL) or mysqldump (MySQL) on a schedule. This captures all notes, users, revisions, and sessions. Automate with cron and store backups off-site.
Upload Backup
Back up the uploads directory or S3 bucket. If using local filesystem, include /hedgedoc/public/uploads in your backup. If using S3, enable versioning and cross-region replication.
# PostgreSQL backup
pg_dump -U hedgedoc -h localhost hedgedoc | gzip > hedgedoc_$(date +%Y%m%d).sql.gz
# Restore
gunzip -c hedgedoc_20260319.sql.gz | psql -U hedgedoc -h localhost hedgedoc
# Backup uploads (local filesystem)
tar -czf hedgedoc_uploads_$(date +%Y%m%d).tar.gz /hedgedoc/public/uploads/
Monitoring and health checks
- Health endpoint —
GET /_healthis a lightweight health check endpoint ideal for load balancers.GET /statusreturns more detailed instance information including online users and note count - Metrics — HedgeDoc exposes a Prometheus-compatible endpoint at
GET /metrics(since 1.8.0), providing the same stats as/statusplus Node.js performance figures. Disable withenableStatsApi: falsein config if not needed - Resource monitoring — Watch Node.js memory usage (can grow with many concurrent WebSocket connections), database connection pool, and disk usage for uploads
Set up alerts on database size growth and upload storage consumption. A busy HedgeDoc instance with many image uploads can consume storage quickly. If using PostgreSQL, also monitor pg_stat_activity for connection pool exhaustion.
HedgeDoc 1.x vs 2.x
HedgeDoc 2.x is a ground-up rewrite of the application. It is not a simple upgrade from 1.x — it is an entirely new codebase with a different architecture, different API, and different feature set.
Architecture comparison
| Aspect | HedgeDoc 1.x | HedgeDoc 2.x |
|---|---|---|
| Backend | Express.js (Node.js) | NestJS (Node.js, TypeScript) |
| Frontend | Server-rendered + jQuery | React SPA (Next.js) |
| Real-time | Socket.IO (Operational Transform) | Y.js (CRDT-based) |
| API | Informal REST API | Formal REST API with OpenAPI spec |
| Editor | CodeMirror 5 | CodeMirror 6 |
| Status | Stable, production-ready (1.10.7) | In development (alpha, ~88% complete) |
Key changes in 2.x
- CRDT instead of OT — 2.x uses Y.js (Conflict-free Replicated Data Type) for real-time sync. This is more robust than Operational Transform and enables offline editing with later sync
- Separate frontend and backend — The React frontend communicates with the NestJS backend via a well-defined API. This enables alternative frontends and better API-first integrations
- Modern editor — CodeMirror 6 provides better mobile support, accessibility, and extensibility
- No direct migration path — There is no automated migration tool from 1.x to 2.x as of early 2026. Notes must be exported and re-imported
As of March 2026, HedgeDoc 2.x is not yet production-ready (alpha stage, approximately 88% of the 2.0 milestone complete). For new production deployments, use HedgeDoc 1.x (latest: 1.10.7). Monitor the 2.x release schedule and plan migration once a stable release is available with a documented migration path. Do not attempt to run 2.x in production without understanding the alpha limitations.
What to tell clients
- Deploy HedgeDoc 1.x for production use today
- The 1.x branch continues to receive security fixes and minor updates
- Plan for an eventual migration to 2.x, but do not block on it
- If the client needs features only in 2.x (offline editing, better mobile), evaluate the alpha carefully and accept the risk
Consultant's Checklist
Pre-deployment
- Choose database backend (PostgreSQL recommended for production)
- Plan upload storage strategy (S3/MinIO for scalability, local for simplicity)
- Determine authentication method (LDAP, OAuth2/OIDC, SAML)
- Configure reverse proxy with WebSocket support (Nginx/Caddy)
- Set
CMD_DOMAINandCMD_PROTOCOL_USESSL=true - Decide on anonymous access policy (
CMD_ALLOW_ANONYMOUS) - Set default note permission (
CMD_DEFAULT_PERMISSION)
Production hardening
- Disable email registration if using external auth (
CMD_ALLOW_EMAIL_REGISTER=false) - Set
CMD_SESSION_SECRETto a strong random value - Enable HSTS and secure cookie flags via reverse proxy
- Set
CMD_CSP_ENABLE=truefor Content Security Policy - Configure rate limiting at the reverse proxy level
- Use non-root container user (default in official image)
Operations
- Automate database backups (daily pg_dump + off-site copy)
- Back up uploads directory or S3 bucket
- Monitor
/_healthendpoint for health checks (/metricsfor Prometheus) - Monitor disk usage for uploads and database growth
- Set up log aggregation (application logs + reverse proxy access logs)
- Plan revision history cleanup for long-running instances
- Document upgrade procedure (Docker image tag update + database migration)