Skip to content

Quickstart

This walks you through running Marrow on your machine for development. For production deployment, see Docker Compose or Cloudflare.

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.

  1. Generate a key: openssl rand -hex 32

  2. Backend — in api/.env:

    API_KEY=your-generated-key-here
  3. Frontend — in web/.env.local:

    MARROW_API_KEY=your-generated-key-here
  4. Start Postgres, API, and web as in steps 2–4 below. The browser sends the key automatically; the app still routes through /login and 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:

Terminal window
cd api
source .venv/bin/activate
marrow export --workspace mydocs --output ./backup.zip
marrow restore ./backup.zip

HTTP API calls use the same key as a header:

Terminal window
curl -H "X-API-Key: your-generated-key-here" http://localhost:8000/api/workspaces/

For a minimal solo stack, set the same key in the root .env used by docker-compose.prod.yml:

API_KEY=your-generated-key-here
MARROW_API_KEY=your-generated-key-here

Leave OIDC vars unset and MARROW_OIDC_ENABLED unset/false. See Docker Compose deployment for the full bring-up sequence.

Full variable reference: Environment variables.

  • Python 3.11+
  • Node.js 20+
  • Docker (for the local PostgreSQL container)
Terminal window
git clone https://github.com/marrow-software/marrow.git
cd marrow
Terminal window
docker compose up -d

This brings up PostgreSQL 16 on port 5433 (so it doesn’t collide with a local Postgres on 5432).

Terminal window
cd api
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env
alembic upgrade head
uvicorn main:app --reload

The 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.

In a second terminal:

Terminal window
cd web
npm install
cp .env.local.example .env.local
npm run dev

The frontend runs at http://localhost:3000.

  • Open http://localhost:3000. The app root (/) redirects to /home; in anonymous dev mode (no OIDC), unauthenticated users are sent to /login and 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.zip and inspect the bundle. Then marrow restore ./out.zip into a fresh database to confirm the round-trip.

The default dev setup runs without authentication. To turn on auth, see: