Getting Started

Quickstart

Get started with Monospace.

Get Started

Note
Monospace runs as a set of containers. Install Docker Compose before you start; every command on this page uses docker compose.

To launch with the default configuration in one command, pipe the quick-start compose file into Docker Compose:

Terminal
curl -fL https://docs.monospace.io/quick-start | docker compose -f - up

This starts the same services as the compose file in step 1, in the foreground. Once Monospace is running, skip to Access the Studio UI.

Configure Docker Compose

Create a docker-compose.yaml file with your Monospace configuration. This example sets up:

  • Monospace — the application
  • PostgreSQL — system database
  • RabbitMQ — event bus for email delivery and, in clustered mode, metadata sync between replicas
  • Redis — query result cache
docker-compose.yaml
name: monospace

services:
  # ---------------------------------------------------------------------------
  # PostgreSQL — system database
  # ---------------------------------------------------------------------------
  postgres:
    image: postgres:17
    restart: unless-stopped
    command: postgres -c 'max_connections=200'
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: monospace
      POSTGRES_DB: monospace
      POSTGRES_HOST_AUTH_METHOD: md5
      POSTGRES_INITDB_ARGS: --auth-host=md5
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d monospace"]
      interval: 5s
      timeout: 5s
      retries: 10
    networks:
      - monospace

  # ---------------------------------------------------------------------------
  # RabbitMQ — event bus (email delivery & clustered-mode metadata sync)
  # ---------------------------------------------------------------------------
  rabbitmq:
    image: rabbitmq:3.13-management
    restart: unless-stopped
    environment:
      RABBITMQ_DEFAULT_USER: monospace
      RABBITMQ_DEFAULT_PASS: monospace
    volumes:
      - rabbitmq_data:/var/lib/rabbitmq
    healthcheck:
      test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
      interval: 10s
      timeout: 5s
      retries: 10
    networks:
      - monospace

  # ---------------------------------------------------------------------------
  # Redis — query result cache
  # ---------------------------------------------------------------------------
  redis:
    image: redis:8.2
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 1s
      timeout: 3s
      retries: 5
    networks:
      - monospace

  # ---------------------------------------------------------------------------
  # Key generator — ephemeral init container that writes JWT + KMS keys once
  # ---------------------------------------------------------------------------
  keygen:
    image: alpine:3.21
    command:
      - sh
      - -c
      - |
        set -e
        mkdir -p /keys
        # Only generate if keys don't already exist
        if ! [ -f /keys/jwt_private.pem ] || ! [ -f /keys/jwt_public.pem ] || ! [ -f /keys/kms_master.key ]; then
          apk add --no-cache openssl > /dev/null
          openssl genpkey -algorithm ED25519 -out /keys/jwt_private.pem
          openssl pkey -in /keys/jwt_private.pem -pubout -out /keys/jwt_public.pem
          openssl rand -base64 32 | tr -d '\n' > /keys/kms_master.key
          echo "Keys generated."
        else
          echo "Keys already exist, skipping generation."
        fi
        chown 65532:65532 /keys/jwt_private.pem /keys/jwt_public.pem /keys/kms_master.key
        chmod 600 /keys/jwt_private.pem /keys/jwt_public.pem /keys/kms_master.key
    volumes:
      - keys_data:/keys

  # ---------------------------------------------------------------------------
  # Monospace — the application
  # ---------------------------------------------------------------------------
  monospace:
    image: monospace/monospace:v1.1.0
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
      rabbitmq:
        condition: service_healthy
      redis:
        condition: service_healthy
      keygen:
        condition: service_completed_successfully
    ports:
      - "8100:8100"
    volumes:
      - keys_data:/keys:ro
      - uploads_data:/monospace/uploads
      # Extensions. The named volume keeps installed extensions across restarts.
      # To install extensions you build on this machine, swap it for the bind
      # mount below and point `monospace extension build --install-to` at
      # ./extensions. Create that directory before starting, so you own it.
      - extensions_data:/monospace/extensions
      # - ./extensions:/monospace/extensions
    environment:
      # Server
      MONOSPACE_HOST: "0.0.0.0"
      MONOSPACE_PORT: "8100"
      MONOSPACE_BASE_URL: "http://localhost:8100"

      # License — leave unset to run on the Starter license
      # MONOSPACE_LICENSE__KEY: "YOUR_LICENSE_KEY"

      # System database
      MONOSPACE_SYSTEM_DATABASE__PROVIDER: "postgres"
      MONOSPACE_SYSTEM_DATABASE__HOST: "postgres"
      MONOSPACE_SYSTEM_DATABASE__PORT: "5432"
      MONOSPACE_SYSTEM_DATABASE__USER: "postgres"
      MONOSPACE_SYSTEM_DATABASE__PASSWORD: "monospace"
      MONOSPACE_SYSTEM_DATABASE__DBNAME: "monospace"

      # File storage (local, inside the container)
      MONOSPACE_SYSTEM_FILE_STORAGE__PROVIDER: "local"
      MONOSPACE_SYSTEM_FILE_STORAGE__SHARED: "true"
      MONOSPACE_SYSTEM_FILE_STORAGE__ROOT_PATH: "/monospace/uploads"

      # Extensions — uncomment to reload an extension when its files change,
      # instead of only at startup. On macOS, changes made on the host through
      # a bind mount can miss the container; run `docker compose restart
      # monospace` if a new install doesn't load.
      # MONOSPACE_EXTENSIONS__AUTO_RELOAD: "true"

      # Redis
      MONOSPACE_REDIS__URL: "redis://redis:6379"

      # RabbitMQ
      MONOSPACE_RABBITMQ__HOST: "rabbitmq"
      MONOSPACE_RABBITMQ__PORT: "5672"
      MONOSPACE_RABBITMQ__USER: "monospace"
      MONOSPACE_RABBITMQ__PASSWORD: "monospace"
      MONOSPACE_RABBITMQ__VHOST: "/"

      # JWT keys (generated by keygen init container)
      MONOSPACE_JWT_PRIVATE_KEY__FILE: "/keys/jwt_private.pem"
      MONOSPACE_JWT_PUBLIC_KEY__FILE: "/keys/jwt_public.pem"

      # KMS (generated by keygen init container)
      MONOSPACE_KMS__TYPE: "monospace"
      MONOSPACE_KMS__MASTER_KEY__FILE: "/keys/kms_master.key"

      # Auth tokens
      MONOSPACE_ACCESS_TOKEN_TTL: "15m"
      MONOSPACE_REFRESH_TOKEN_TTL: "7days"

      # Cookie — disable Secure flag so HTTP works out of the box
      MONOSPACE_COOKIE_SECURE: "false"
    networks:
      - monospace

volumes:
  postgres_data:
  rabbitmq_data:
  keys_data:
  uploads_data:
  extensions_data:

networks:
  monospace:

Start the Services

Launch all services using Docker Compose:

Terminal
docker compose up -d

Wait for all containers to start (this may take 1-2 minutes on first run).

Verify services are running:

Terminal
docker compose ps
Note
Without a license key, Monospace runs on the Starter license. To apply a purchased license, set MONOSPACE_LICENSE__KEY and restart. See Licensing.

Access the Studio UI

Once all services are running, access the Monospace Studio interface:

Studio UI: http://localhost:8100

A fresh instance has no users, so Studio opens onboarding instead of a sign-in page. Create the first administrator account:

  • Full Name
  • Email
  • Password

Accept the End User License Agreement, then click Continue. Studio signs you in and moves on to creating your first workspace.

Create Your First Workspace

Your organization is the top-level tenant. Within an organization you have workspaces that contain your schemas and data source connections.

Onboarding asks for your first workspace:

  • Workspace Name — the name shown in Studio
  • Workspace URL — the slug in the workspace's Studio and API URLs, filled in from the name
  • Workspace Logo — optional

Click Continue to create the workspace.

Configure a Data Source

Onboarding then asks you to add a data source. Every workspace includes a built-in PostgreSQL data source, Workspace Database, which is enough for local development. Click I'll do this later to skip this screen.

To connect an existing database instead, click Add Data Source, choose a connector, and enter the connection details. Connecting multiple databases to a single workspace is a core capability of the platform.

Note
When connecting an existing database, Monospace uses Database Introspection to map your schema to Collections. Select Continue to choose which namespaces and collections to import, or choose Connect Entire Database from its menu to import everything.

To add more data sources later, go to Data Model > Data Sources and click Add Source.

The last onboarding screen, Connect to your workspace, shows how to connect to the workspace over MCP, the SDK, or REST. Click Finish setup to open the workspace.

Configure a Collection

Navigate to Data Model to view your Collections. If you connected an existing database, the collections you imported already appear there thanks to Database Introspection.

Each collection has tabs for managing Columns, Relations, and other configuration.

To create a new collection, click Add Collection and specify a name.

Once created, you can add fields to define the shape of your data.

Manage Your Data

Head to the Content module to browse, create, and edit items within your collections.

Next Steps

Now you're up and running with the basics. Explore the platform further:

MonospaceThe governed API layer for every app, person, and agent.

Copyright © 2026 Monospace Inc.