docs / grandstack / Reference

Configuration

How the stack is wired and every setting that matters, with pointers to the repo that owns each one.

Where to run this. Docker Compose commands run inside a clone of this repository (git clone https://github.com/grand-stack/grandstack, then cd grandstack), with the repositories it builds cloned beside it. The quickstart has the exact steps.

Compose services

compose.yaml defines three services:

ServiceImage or buildPorts (host:container)Notes
neo4jneo4j:2026.10-community7474:7474 (browser), 7687:7687 (bolt)Data in the named volume neo4j-data. Healthcheck runs cypher-shell; the server waits for it.
serverbuilt from ../grandstack-server4000:4000Needs Neo4j healthy first.
webbuilt from ../grandstack-web3000:8080Static files served by unprivileged nginx.

Because the builds use ../grandstack-server and ../grandstack-web, the three repositories must sit side by side in one folder. The auth setup also builds from ../grandstack-auth, the agents setup from ../grandstack-agents, and the federation setup from ../grandstack-federation, so those repositories must be there too if you use them.

With authentication: compose.auth.yaml

An override file, used together with compose.yaml: docker compose -f compose.yaml -f compose.auth.yaml up --build. Development only. It changes and adds:

ServiceChange
keycloak (new)quay.io/keycloak/keycloak:26.8.1 in dev mode, imports ../grandstack-auth/keycloak/grandstack-realm.json, issuer fixed to http://localhost:8081/realms/grandstack, port 8081, healthcheck
gateway (new)built from ../grandstack-auth/gateway, in front of the server, port 4000
auth-client (new)the demo client, built from ../grandstack-auth/client, port 3001
serverno host port; gets AUTH_JWKS_URL, AUTH_ISSUER, AUTH_AUDIENCE, SCHEMA_EXTRA_PATHS, SETUP_CYPHER_PATHS; mounts auth.graphql and auth-setup.cypher; a healthcheck; waits for Keycloak
webunchanged: still http://localhost:3000, still calling http://localhost:4000/graphql, which is now the gateway, so it is an anonymous client

Ports in the auth setup: 3000 web, 3001 demo client, 4000 gateway, 8081 Keycloak, 7474 and 7687 Neo4j. Everything else about the auth settings (roles, permissions, rules, the issuer-versus-keys addresses) is documented in grandstack-auth (docs/how-it-works.md, docs/role-and-scope-model.md).

With agents: compose.agents.yaml

An override file, used together with compose.yaml: docker compose -f compose.yaml -f compose.agents.yaml up --build. It adds one service:

ServiceDetail
agents-mcp (new)built from ../grandstack-agents; MCP over streamable HTTP at http://localhost:4100/mcp; GRAPHQL_URL=http://server:4000/graphql; ALLOW_MUTATIONS from AGENTS_ALLOW_MUTATIONS (default false)

It talks to the open server, so it needs the default stack and has no auth of its own. Keep port 4100 on your machine. To use it with the auth setup, give it a token as described in grandstack-agents (docs/adding-auth.md).

With federation: compose.federation.yaml

An override file, used together with compose.yaml: docker compose -f compose.yaml -f compose.federation.yaml up --build. It changes and adds:

ServiceDetail
serverFEDERATION=true; mounts ../grandstack-federation/schema/federation.graphql (SCHEMA_EXTRA_PATHS) and seed/wikipedia-links.cypher (SETUP_CYPHER_PATHS); host port 4001 instead of 4000; a healthcheck
wikipedia (new)built from ../grandstack-federation; the Wikipedia subgraph, port 4010
gateway (new)built from ../grandstack-federation/gateway; serves the composed supergraph on port 4000; waits for the server and the Wikipedia subgraph
webunchanged: still http://localhost:3000, still calling http://localhost:4000/graphql, which is now the gateway

It needs internet for the Wikipedia part, and it replaces the default, auth and agents setups on port 4000. Ports in the federation setup: 3000 web, 4000 gateway, 4001 Neo4j subgraph, 4010 Wikipedia subgraph, 7474 and 7687 Neo4j.

Settings you are likely to change

SettingWhereDefaultEffect
NEO4J_PASSWORD.env (copy from .env.example)grandstack-devNeo4j password; used by Neo4j, the healthcheck and the server. Set before the first start: Neo4j stores the password in the volume.
Server variables (SEED, SEED_PATH, SEED_PROBE_LABEL, REFRESH_COUNTS, CORS_ORIGIN, NEO4J_DATABASE, AUTH_*, SCHEMA_EXTRA_PATHS, SETUP_CYPHER_PATHS, …)server.environment in compose.yamlsee the server’s docs/configuration.mdHow the server behaves. Add the ones you need under server.environment.
VITE_GRAPHQL_URLweb.build.args in compose.yamlhttp://localhost:4000/graphqlThe URL the browser uses to reach the server. Fixed at build time, so rebuild web after changing it.
Host portsports in compose.yaml3000, 4000, 7474, 7687Change the left side to avoid clashes. If you move the web port, also set the server’s CORS_ORIGIN to the new web origin. If you move the server port, change VITE_GRAPHQL_URL.

The server’s own variable list lives in docs/configuration.md in grandstack-server; it is the source of truth.

Everyday commands

docker compose up --build        # start everything (first run builds the images)
docker compose up -d             # start in the background
docker compose logs -f server    # follow one service
docker compose down              # stop, keep the data
docker compose down -v           # stop and DELETE the Neo4j data (the sample reseeds on next start)

Use your own schema and data with an override file: build your own app.

Podman

On macOS docker may actually be Podman. If commands cannot connect, start the VM with podman machine start and set DOCKER_HOST to the socket it prints. Compose works the same way. The stack in this repo was developed and tested under Podman.

Resetting data

The default stack has no authentication, and the app can edit and delete everything. (With the auth setup, editing needs a login with the right role.) To get the sample data back, run docker compose down -v then docker compose up (add the -f files you started with). A seed newer than the loaded one reloads by itself on server start; see the server’s docs/seeding.md.

If a port is already in use

If you already run Neo4j (or anything else) on one of these ports, compose may fail to bind it, or a client may reach the wrong server: on the machine this was built on, a local Neo4j listened on 127.0.0.1:7687 while the container’s forwarded port was bound as well, so bolt://localhost:7687 could hit either one. The stack itself is unaffected, because the server reaches Neo4j over the compose network (bolt://neo4j:7687). To avoid confusion, change the left side of the port mapping in compose.yaml (for example "17687:7687") before connecting a tool from your machine, and check what is listening with lsof -nP -iTCP:7687 -sTCP:LISTEN.

Ports at a glance

URLWhat
http://localhost:3000Web app
http://localhost:4000/graphqlGraphQL API and GraphiQL
http://localhost:4001/graphqlNeo4j subgraph (federation setup only)
http://localhost:4010/graphqlWikipedia subgraph (federation setup only)
http://localhost:4100/mcpAgents MCP server (agents setup only; /healthz for a check)
http://localhost:7474Neo4j Browser (user neo4j, password from .env)
http://localhost:3001Auth demo client (auth setup only)
http://localhost:8081Keycloak (auth setup only; admin console admin / admin)
bolt://localhost:7687Neo4j Bolt

Source: grandstack/docs/configuration.md (this page is a copy; edit it in the repository)