Memgraph ZeroMemGQLDocker Compose

Docker Compose - Complete Setup

This guide runs the full MemGQL stack using Docker Compose: Memgraph as the graph backend, MemGQL as the federated query engine, Memgraph Lab for visual exploration, PostgreSQL as a relational backend, the MCP server for AI agent integration, and structured2graph to create the mappings.

Prerequisites

Architecture

                                                ┌──────────────┐
┌──────────────┐          ┌──────────────┐ bolt │              │
│  mgconsole   │──bolt───▶│              │─────▶│  Memgraph    │
└──────────────┘          │              │      │         :7687│
                          │              │      └──────────────┘
┌──────────────┐          │    MemGQL    │
│ Memgraph Lab │──bolt───▶│              │
│         :3000│          │        :7688 │      ┌──────────────┐
└──────────────┘          │              │ sql  │              │
                          │              │─────▶│  PostgreSQL  │
┌──────────────┐          │              │      │         :5432│
│  MCP Server  │──bolt───▶│              │      └──────────────┘
│         :8000│          └──────────────┘
└──────────────┘

Clients (mgconsole, Bolt drivers, Lab) connect to MemGQL on port 7688. MemGQL translates GQL and routes queries to the configured backends.

1. Create the Docker network

All services communicate over a shared Docker network:

docker network create memgql-net

2. Create the PostgreSQL init files

MemGQL needs a graph mapping to translate graph patterns into SQL. Create these two files next to your docker-compose.yml:

pg_init.sql creates the relational tables:

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    email TEXT
);
 
CREATE TABLE friend_of (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES users(id),
    friend_id INTEGER NOT NULL REFERENCES users(id),
    UNIQUE (user_id, friend_id)
);

pg_mapping.json is a graph mapping body (vertices + edges) that maps the tables to graph labels on the pg connector:

{
  "vertices": [
    {
      "label": "User",
      "mappedTableSource": {
        "connector": "pg",
        "table": "users",
        "metaFields": {
          "id": "id"
        }
      },
      "attributes": [
        {
          "name": "name"
        },
        {
          "name": "email"
        }
      ]
    }
  ],
  "edges": [
    {
      "label": "FRIEND_OF",
      "from": "User",
      "to": "User",
      "mappedTableSource": {
        "connector": "pg",
        "table": "friend_of",
        "metaFields": {
          "id": "id",
          "from": "user_id",
          "to": "friend_id"
        }
      }
    }
  ]
}

3. Docker Compose file

Save the following as docker-compose.yml:

services:
  memgql:
    image: ${MEMGQL_IMAGE:-memgraph/memgql:0.8.0}
    container_name: memgql
    ports:
      - "7688:7688"
    environment:
      CONNECTOR_TYPE: ${CONNECTOR_TYPE:-multi}
      MEMGRAPH_URI: memgraph:7687
      BOLT_LISTEN_ADDR: 0.0.0.0:7688
      # To enable enterprise features, set these in a .env file or via CLI:
      #   MEMGQL_ENTERPRISE_LICENSE=mglk-...
      #   MEMGQL_ORGANIZATION_NAME=your-org
    volumes:
      - memgql-mappings:/mappings
      - ./pg_mapping.json:/mappings/pg_mapping.json
    healthcheck:
      test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/localhost/7688'"]
      interval: 2s
      timeout: 2s
      retries: 15
      start_period: 3s
    depends_on:
      memgraph:
        condition: service_healthy
    networks:
      - memgql-net
 
  memgql-init:
    image: memgraph/mgconsole:1.6.0
    container_name: memgql-init
    entrypoint:
      - sh
      - -c
      - |
        echo "ADD CONNECTOR mg TYPE memgraph URI 'memgraph:7687' GRAPH memgraph;" | mgconsole --host memgql --port 7688 &&
        echo "ADD CONNECTOR pg TYPE postgres URI 'host=postgres user=postgres password=postgres dbname=postgres';" | mgconsole --host memgql --port 7688 &&
        echo "CREATE GRAPH social FROM FILE '/mappings/pg_mapping.json';" | mgconsole --host memgql --port 7688 &&
        echo "MemGQL bootstrap complete."
    depends_on:
      memgql:
        condition: service_healthy
      postgres:
        condition: service_healthy
    networks:
      - memgql-net
    restart: "no"
 
  memgraph:
    image: memgraph/memgraph-mage:3.12.0
    container_name: memgraph
    ports:
      - "7687:7687"
    command: --log-level=TRACE --also-log-to-stderr
    environment:
      MEMGRAPH_ENTERPRISE_LICENSE: ${MEMGRAPH_ENTERPRISE_LICENSE:-}
      MEMGRAPH_ORGANIZATION_NAME: ${MEMGRAPH_ORGANIZATION_NAME:-}
    healthcheck:
      test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/localhost/7687'"]
      interval: 2s
      timeout: 2s
      retries: 15
      start_period: 3s
    networks:
      - memgql-net
 
  lab:
    image: memgraph/lab:3.12.0
    container_name: lab
    ports:
      - "3000:3000"
    environment:
      QUICK_CONNECT_MG_HOST: memgql
      QUICK_CONNECT_MG_PORT: 7688
    depends_on:
      - memgql
    networks:
      - memgql-net
 
  postgres:
    image: postgres:18
    container_name: postgres
    ports:
      - "5432:5432"
    environment:
      POSTGRES_PASSWORD: postgres
    volumes:
      - ./pg_init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 2s
      timeout: 2s
      retries: 15
      start_period: 3s
    networks:
      - memgql-net
 
  memgql-mcp:
    image: memgraph/memgql-mcp:0.2.0
    container_name: memgql-mcp
    ports:
      - "8000:8000"
    environment:
      MCP_TRANSPORT: streamable-http
      MEMGQL_URL: bolt://memgql:7688
    depends_on:
      - memgql
    networks:
      - memgql-net
 
  structured2graph:
    image: memgraph/structured2graph:0.2.2
    container_name: structured2graph
    entrypoint: ["sleep", "infinity"]
    volumes:
      - memgql-mappings:/mappings
    depends_on:
      memgraph:
        condition: service_healthy
    networks:
      - memgql-net
 
volumes:
  memgql-mappings:
    name: memgql-mappings
 
networks:
  memgql-net:
    name: memgql-net
    external: true

4. Start all services

docker compose up -d

Wait for all containers to become healthy:

docker compose ps

You should see all eight services running: memgraph, memgql, memgql-init, lab, postgres, memgql-mcp, and structured2graph. The memgql-init container registers both connectors and exits; this is expected.

5. Connect with mgconsole

mgconsole --port 7688

The mg and pg connectors and the social graph (over PostgreSQL) are already registered by the memgql-init service. We add the native Memgraph graph below, then query each by its labels: routing picks the graph, so no USE is required.

Seed Memgraph with developers

Register a native graph over the Memgraph connector, then insert developers (the Developer label routes to dev):

CREATE GRAPH dev FROM '{
  "vertices": [ { "label": "Developer", "mappedGraphSource": { "connector": "mg" } } ],
  "edges":    [ { "label": "FOLLOWS", "from": "Developer", "to": "Developer", "mappedGraphSource": { "connector": "mg" } } ]
}';
INSERT
  (lana:Developer {name: "Lana", level: "senior", yoe: 12}),
  (marco:Developer {name: "Marco", level: "mid", yoe: 5}),
  (priya:Developer {name: "Priya", level: "senior", yoe: 9}),
  (tom:Developer {name: "Tom", level: "junior", yoe: 1}),
  (sara:Developer {name: "Sara", level: "mid", yoe: 4}),
  (lana)-[:FOLLOWS]->(priya),
  (marco)-[:FOLLOWS]->(sara),
  (sara)-[:FOLLOWS]->(lana),
  (tom)-[:FOLLOWS]->(marco),
  (priya)-[:FOLLOWS]->(lana);
MATCH (d:Developer) RETURN d.name, d.level, d.yoe;
MATCH (a:Developer)-[:FOLLOWS]->(b:Developer) RETURN a.name, b.name;

Seed PostgreSQL with users

Insert users; the User label routes to the social graph (PostgreSQL):

INSERT (alice:User {name: "Alice", email: "alice@example.com"});
INSERT (bob:User {name: "Bob", email: "bob@example.com"});
INSERT (charlie:User {name: "Charlie", email: "charlie@example.com"});
INSERT (diana:User {name: "Diana", email: "diana@example.com"});

Add friendships:

MATCH (a:User {name: "Alice"}), (b:User {name: "Bob"}) INSERT (a)-[:FRIEND_OF]->(b);
MATCH (a:User {name: "Alice"}), (b:User {name: "Charlie"}) INSERT (a)-[:FRIEND_OF]->(b);
MATCH (a:User {name: "Bob"}), (b:User {name: "Diana"}) INSERT (a)-[:FRIEND_OF]->(b);
MATCH (a:User {name: "Charlie"}), (b:User {name: "Diana"}) INSERT (a)-[:FRIEND_OF]->(b);
MATCH (u:User) RETURN u.name, u.email;
MATCH (u:User)-[:FRIEND_OF]->(f:User) RETURN u.name, f.name;

Query across both backends

MATCH (d:Developer)-[:FOLLOWS]->(f:Developer)
  RETURN d.name AS source, "FOLLOWS" AS rel, f.name AS target;
MATCH (u:User)-[:FRIEND_OF]->(f:User)
  RETURN u.name AS source, "FRIEND_OF" AS rel, f.name AS target;

6. Open Memgraph Lab

Open http://localhost:3000 in a browser. Lab is pre-configured to connect to MemGQL on port 7688; click Quick Connect and start exploring visually.

7. Create mappings with structured2graph

The structured2graph container generates JSON mapping files that tell MemGQL how to translate graph patterns into relational queries. It runs with sleep infinity so you can exec into it on demand.

Shell into the container:

docker exec -it structured2graph bash

Inside the container, configure and run:

# Copy the example config and edit it with your connection details
cp .env.example .env
 
# TODO: Adjust the .env file with the right values.
 
# Generate the mapping file (written to the shared /mappings volume)
structured2graph --mapping /mappings/social.json

Once the mapping is generated, it’s available to MemGQL via the shared memgql-mappings volume at /mappings/social.json. You can now load it from a MemGQL session.

8. MCP server for AI agents

The MCP server exposes MemGQL over the Model Context Protocol on http://localhost:8000. AI agents and tools that support MCP can connect to run GQL queries against any backend wired into MemGQL.

Port summary

ServicePortProtocol
Memgraph7687Bolt
MemGQL7688Bolt
Memgraph Lab3000HTTP
PostgreSQL5432PostgreSQL wire
MemGQL MCP8000HTTP (streamable)

Stopping everything

docker compose down

To also remove the shared volume:

docker compose down -v