Skip to content

withcomposure/composure

Repository files navigation

🐚 Composure

Tests codecov License: MIT TypeScript Node.js PRs Welcome

Composure is a self-hostable, collaborative editor for LaTeX, Typst, Markdown, and more.

Getting Started

Full self-hosting docs are coming soon. In the meantime:

git clone https://github.com/withcomposure/composure
cd composure
docker compose -f docker-compose.yml -f docker-compose.db.yml up --build

Deployment Modes

Composure supports three deployment styles:

  1. Hetzner + external PostgreSQL (Neon, RDS, etc.)
    • Base compose file only.
docker compose up --build
  1. Hetzner + external PostgreSQL + Cloudflare Pages frontend
    • Use the split override to build the API-only backend image target.
docker compose --env-file .env.split -f docker-compose.yml -f docker-compose.split.yml up --build
  1. Self-host everything (local PostgreSQL + backend + frontend)
    • Add the DB overlay.
docker compose -f docker-compose.yml -f docker-compose.db.yml up --build

For split mode, copy .env.split.example to .env.split and set at least:

  • CORS_ORIGIN=https://your-app.pages.dev
  • BACKEND_URL=https://api.yourdomain.com
  • FRONTEND_URL=https://your-app.pages.dev
  • API_BASE_PATH=/
  • SERVE_FRONTEND=false

Cookie behavior in split mode:

  • If FRONTEND_URL and BACKEND_URL are same-site (for example app.example.com + api.example.com), defaults are SameSite=Lax for sessions and SameSite=Strict for guest cookies.
  • If they are truly cross-site (for example app.pages.dev + api.yourdomain.com), cookies automatically switch to SameSite=None.
  • You can override explicitly with SESSION_COOKIE_SAME_SITE and GUEST_COOKIE_SAME_SITE (strict, lax, or none).
  • SameSite=None requires HTTPS in production.

Requires Node 24.

Caddyfile Deployment Examples

The examples below use Caddy environment placeholders (for example {$COMPOSURE_DOMAIN}) so you can avoid hard-coded domains, ports, and upstream URLs.

Shared Notes

  • Caddy auto-handles websocket upgrades when using reverse_proxy, so no extra websocket directives are needed for collaboration.
  • PostgreSQL is not HTTP and should not be proxied through Caddy. Keep it on a private network and expose only backend/frontend HTTP services.
  • Keep API_BASE_PATH (backend) and VITE_API_URL (frontend) aligned.

1) Host Frontend + Backend + DB (single host, backend serves frontend)

Use this with:

  • docker compose -f docker-compose.yml -f docker-compose.db.yml up --build
  • SERVE_FRONTEND=true
{
   email {$ACME_EMAIL}
}

{$COMPOSURE_DOMAIN} {
   encode zstd gzip
   reverse_proxy {$COMPOSURE_BACKEND_UPSTREAM}
}

Typical env values:

  • COMPOSURE_BACKEND_UPSTREAM=127.0.0.1:8080 (or composure:8080 if Caddy is in the same Docker network)
  • API_BASE_PATH=/api (default) or /

2) Host Frontend + Backend on Separate Subdomains

Use this when frontend and backend are separate services:

  • app on app.example.com
  • API on api.example.com
{
   email {$ACME_EMAIL}
}

{$COMPOSURE_APP_DOMAIN} {
   encode zstd gzip
   reverse_proxy {$COMPOSURE_FRONTEND_UPSTREAM}
}

{$COMPOSURE_API_DOMAIN} {
   encode zstd gzip
   reverse_proxy {$COMPOSURE_BACKEND_UPSTREAM}
}

Recommended app env alignment:

  • Backend: SERVE_FRONTEND=false
  • Backend: CORS_ORIGIN=https://${COMPOSURE_APP_DOMAIN}
  • Backend: BACKEND_URL=https://${COMPOSURE_API_DOMAIN}
  • Backend: FRONTEND_URL=https://${COMPOSURE_APP_DOMAIN}
  • Backend: API_BASE_PATH=/ (or /api, but then include that in VITE_API_URL)
  • Frontend: VITE_API_URL=https://${COMPOSURE_API_DOMAIN} when API_BASE_PATH=/
  • Frontend: VITE_API_URL=https://${COMPOSURE_API_DOMAIN}/api when API_BASE_PATH=/api
  • Frontend: when VITE_API_URL is absolute, API requests are sent with credentials so session cookies persist between app/api subdomains.
  • Cookie defaults are already correct for same-site subdomains. For custom behavior, set SESSION_COOKIE_SAME_SITE / GUEST_COOKIE_SAME_SITE.

3) Host Frontend + Backend on One Domain (Path-Based Routing)

Use this when frontend and backend are separate upstreams but share one public domain.

{
   email {$ACME_EMAIL}
}

{$COMPOSURE_DOMAIN} {
   encode zstd gzip

   @backend path /health /assets/* /api/* /v1/*
   handle @backend {
      reverse_proxy {$COMPOSURE_BACKEND_UPSTREAM}
   }

   handle {
      reverse_proxy {$COMPOSURE_FRONTEND_UPSTREAM}
   }
}

Notes:

  • /api/* covers default API_BASE_PATH=/api.
  • /v1/* covers API_BASE_PATH=/.
  • If you use a custom API prefix like /my/api, add /my/api/* to @backend and set VITE_API_URL=/my/api.

4) Host Backend Only (API Edge, Frontend Hosted Elsewhere)

Useful for split deployments where frontend is on Cloudflare Pages, Vercel, Netlify, etc.

{
   email {$ACME_EMAIL}
}

{$COMPOSURE_API_DOMAIN} {
   encode zstd gzip

   @allowed path /health /assets/* /api/* /v1/*
   handle @allowed {
      reverse_proxy {$COMPOSURE_BACKEND_UPSTREAM}
   }

   respond 404
}

Recommended backend env alignment:

  • SERVE_FRONTEND=false
  • CORS_ORIGIN=https://${COMPOSURE_FRONTEND_ORIGIN}
  • BACKEND_URL=https://${COMPOSURE_API_DOMAIN}
  • FRONTEND_URL=https://${COMPOSURE_FRONTEND_ORIGIN}
  • API_BASE_PATH=/ (common for split mode) or /api
  • Ensure frontend VITE_API_URL points to this API origin (including any API base path).
  • For cross-site frontend/API pairs, run over HTTPS so SameSite=None cookies are accepted by browsers.

5) Private LAN / Homelab with Internal TLS

For non-public DNS labs where you still want HTTPS, Caddy can issue internal certs.

{$COMPOSURE_LAN_DOMAIN} {
   tls internal
   reverse_proxy {$COMPOSURE_BACKEND_UPSTREAM}
}

Example:

  • COMPOSURE_LAN_DOMAIN=composure.home.arpa
  • COMPOSURE_BACKEND_UPSTREAM=127.0.0.1:8080

If you later move to public DNS, remove tls internal and set ACME_EMAIL to use public ACME certificates.

Features & Roadmap

User Accounts

  • User account system
  • Profile photos
  • Password authentication
  • User session management
  • Account self-deletion with confirmation
  • Second factor authentication (TOTP, WebAuthn)
  • Force users to change a temporary password on their next login

Server Administration

  • Admin dashboard
  • User management (view, search, add, delete, suspend)
  • Admins can generate password reset links for users
  • Account deletion
  • Global or per-user project limits
  • Invite link management
  • Open and invite-only signup modes
  • Compiler concurrency
  • Recent jobs monitoring
  • Upload size and rate limits
  • Server monitoring statistics (beyond recent jobs)
  • SMTP configuration for email notifications (emails work, not wired up yet)

Dashboard

  • Project creation and deletion
  • Search and sorting
  • Grid and list views
  • New project templates
  • Recent activity feed
  • Shared projects listing
  • Pinned projects listing
  • Recently deleted (restore, permanent delete, auto-purge)

File Tree

  • File upload
  • Folders
  • File move, rename, and delete
  • Image/PDF preview

Comments

  • Multi-line comments
  • Comment threads (one level, for now)
  • Comment editing and deletion

Collaboration

  • Real-time collaboration with multiple users and labeled cursors
  • View, comment, and edit collaboration modes
  • Granular access control per project, with shareable links
  • Presence indicators on the dashboard

Drafting

  • Brace auto-closing, with some LaTeX-aware smarts
  • Highlighting text also highlights other occurrences of the same text
  • Find and replace
  • Suggestion for LaTeX and Typst commands and environments
  • File path and bibliography auto-complete
  • Multiple cursors (alt/opt to add, and shift for rectangular selection)
  • User snippets library
  • Editor tabs
  • Split view
  • Searchable visual math symbol palette (sensitive to file format)

Compile and Export

  • Pluggable renderer architecture
  • Support for multiple rendering workers to balance load
  • Compile LaTeX to PDF preview (tectonic)
  • Compile Typst to PDF preview (typst)
  • Export to PDF, HTML, Microsoft Word (pandoc)
  • Export to ArXiv submission format

Version Control

  • Git integration (persisted bare repo)
  • User-generated snapshots with commit messages
  • Auto-commit on time interval
  • Auto-commit on compile
  • Auto-commit on export
  • Diff viewer for text files
  • Per-file restore
  • Point-in-time (full commit) restore
  • Remote Git repository sync support (e.g. GitHub, GitLab)

Design

  • Light and dark themes
  • Full mobile support
  • Context-sensitive right-click support (in most places)
  • Global toast notification system

Documentation

  • One-click deploy docs
  • Quick start / self-hosting guide
  • Tech stack blurb and architecture overview
  • Code contribution guidelines
  • Visual demo or walkthrough

Hosting

  • Configurable CORS origins

Contributing

Contributions are welcome! Whether it's a bug report, feature suggestion, or pull request, please check out the Contributing Guide to get started.

License

Composure is available under the MIT License.

About

A self-hostable, collaborative editor for LaTeX, Typst, Markdown, and more.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors