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 schema 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 (
    user_id INTEGER NOT NULL REFERENCES users(id),
    friend_id INTEGER NOT NULL REFERENCES users(id),
    PRIMARY KEY (user_id, friend_id)
);

pg_mapping.json — tells MemGQL how tables map to graph labels:

{
  "nodes": [
    {
      "label": "User",
      "table": "users",
      "id_column": "id",
      "properties": {
        "name": "name",
        "email": "email"
      }
    }
  ],
  "edges": [
    {
      "rel_type": "FRIEND_OF",
      "table": "friend_of",
      "source_column": "user_id",
      "target_column": "friend_id",
      "source_label": "User",
      "target_label": "User"
    }
  ]
}

3. Docker Compose file

Save the following as docker-compose.yml:

services:
  memgql:
    image: memgraph/memgql:0.3.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.5.1
    container_name: memgql-init
    entrypoint:
      - sh
      - -c
      - |
        echo "ADD CONNECTOR mg TYPE memgraph URI 'memgraph:7687' GRAPH memgraph;" | mgconsole --host memgql --port 7688 &&
        echo "CONNECT mg AS mg_conn;" | mgconsole --host memgql --port 7688 &&
        echo "ADD MAPPING pg_social FROM '/mappings/pg_mapping.json';" | mgconsole --host memgql --port 7688 &&
        echo "ADD CONNECTOR pg TYPE postgres URI 'host=postgres user=postgres password=postgres dbname=postgres' MAPPING pg_social;" | mgconsole --host memgql --port 7688 &&
        echo "CONNECT pg AS pg_conn;" | 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.9.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.9.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

Both the Memgraph and PostgreSQL connectors are already registered and connected by the memgql-init service. You can start querying right away.

Seed Memgraph with developers

SET DEFAULT CONNECTION mg_conn;
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

Switch to the PostgreSQL connection and insert users:

SET DEFAULT CONNECTION pg_conn;
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

Each connection is queried independently — MemGQL routes the query to the right backend based on the USE CONNECTION clause:

USE CONNECTION mg_conn
  MATCH (d:Developer)-[:FOLLOWS]->(f:Developer)
  RETURN d.name AS source, "FOLLOWS" AS rel, f.name AS target;
USE CONNECTION pg_conn
  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