Quickstart
This walks you through running Marrow on your machine for development. For production deployment, see Docker Compose or Cloudflare.
Solo self-host without OIDC
Section titled “Solo self-host without OIDC”If you want a single-user instance with no identity provider — common for beachhead self-hosters auditing the bundle — use a static API key instead of OIDC.
Local dev (API + web)
Section titled “Local dev (API + web)”-
Generate a key:
openssl rand -hex 32 -
Backend — in
api/.env:API_KEY=your-generated-key-here -
Frontend — in
web/.env.local:MARROW_API_KEY=your-generated-key-here -
Start Postgres, API, and web as in steps 2–4 below. The browser sends the key automatically; the app still routes through
/loginand lands on/workspaces(there is no separate identity — the API key is a shared superuser credential, not a per-user login).
CLI talks to Postgres directly (not the HTTP API). With api/.env configured and venv active:
cd apisource .venv/bin/activatemarrow export --workspace mydocs --output ./backup.zipmarrow restore ./backup.zipHTTP API calls use the same key as a header:
curl -H "X-API-Key: your-generated-key-here" http://localhost:8000/api/workspaces/Docker Compose (solo production)
Section titled “Docker Compose (solo production)”For a minimal solo stack, set the same key in the root .env used by docker-compose.prod.yml:
API_KEY=your-generated-key-hereMARROW_API_KEY=your-generated-key-hereLeave OIDC vars unset and MARROW_OIDC_ENABLED unset/false. See Docker Compose deployment for the full bring-up sequence.
Full variable reference: Environment variables.
Prerequisites
Section titled “Prerequisites”- Python 3.11+
- Node.js 20+
- Docker (for the local PostgreSQL container)
1. Clone the repo
Section titled “1. Clone the repo”git clone https://github.com/marrow-software/marrow.gitcd marrow2. Start PostgreSQL
Section titled “2. Start PostgreSQL”docker compose up -dThis brings up PostgreSQL 16 on port 5433 (so it doesn’t collide with a local Postgres on 5432).
3. Backend setup
Section titled “3. Backend setup”cd apipython -m venv .venv && source .venv/bin/activatepip install -e ".[dev]"cp .env.example .envalembic upgrade headuvicorn main:app --reloadThe API is fail-closed — it refuses to start unless an auth method is configured. For a zero-config local instance, uncomment MARROW_ALLOW_ANONYMOUS=true in api/.env (localhost only — it bypasses all access control). Alternatively set an API_KEY (see Solo self-host without OIDC) or configure OIDC.
The API runs at http://localhost:8000.
4. Frontend setup
Section titled “4. Frontend setup”In a second terminal:
cd webnpm installcp .env.local.example .env.localnpm run devThe frontend runs at http://localhost:3000.
5. Try it
Section titled “5. Try it”- Open
http://localhost:3000. The app root (/) redirects to/home; in anonymous dev mode (no OIDC), unauthenticated users are sent to/loginand then/workspaces. - Create a workspace, then a space, then add folders and pages inside that space.
- Type into the BlockNote editor — it auto-saves after 2 seconds and creates a revision on every save.
- Hover over a folder in the sidebar to create child folders and pages via the
+buttons. - Try
cd api && marrow export --workspace <slug> --output ./out.zipand inspect the bundle. Thenmarrow restore ./out.zipinto a fresh database to confirm the round-trip.
Configuration
Section titled “Configuration”The default dev setup runs without authentication. To turn on auth, see:
- Environment variables — full reference.
- OIDC — sign-in via Google, Keycloak, etc.