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-net2. 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: true4. Start all services
docker compose up -dWait for all containers to become healthy:
docker compose psYou 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 7688Both 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 bashInside 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.jsonOnce 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
| Service | Port | Protocol |
|---|---|---|
| Memgraph | 7687 | Bolt |
| MemGQL | 7688 | Bolt |
| Memgraph Lab | 3000 | HTTP |
| PostgreSQL | 5432 | PostgreSQL wire |
| MemGQL MCP | 8000 | HTTP (streamable) |
Stopping everything
docker compose downTo also remove the shared volume:
docker compose down -v