Building on GRANDstack, not beside it
GRANDstack is a set of building blocks that people shape into a solution of their own: a server image driven by a schema file, a federation gateway, an auth layer, an agent endpoint, a web app, and compose files that put them together. A new repository or setup should be made from those blocks. If it copies one, forks one, or re-implements one, it is a silo: it cannot be combined with the others, it drifts, and nobody who learns GRANDstack can reuse what they learned.
This page is for coding agents and the people directing them, and for anyone adding a repository or a setup. Read it before you create a repository, a compose file, a server, a gateway or a docs structure.
The rule
Use what is here. If a block is missing something, improve the block. Only what is genuinely new lives in the new repository.
| You need | Use this block | Do not |
|---|---|---|
| A GraphQL API over Neo4j | grandstack-server (the image), configured with a schema file and environment variables | write another server, or copy its code |
| A different schema, setup or sample data | A model (MODEL=<name>, a mounted models/<name>/ folder), or SCHEMA_PATH, SCHEMA_EXTRA_PATHS, SETUP_CYPHER_PATHS, SEED=false | fork the server to change its schema |
| A read-only copy of an API | READ_ONLY=true on a second server | build a second schema by hand |
| One API from several services | grandstack-federation’s gateway image, with your own supergraph.graphql and gateway.config.ts mounted over its own | build another gateway image |
| Login and access rules | grandstack-auth (the gateway, Keycloak, schema rules) | write your own sign-in unless the block cannot do it, and then say why |
| Agents using the API | grandstack-agents (the MCP server) | write another tool server |
| A browser front end | A web app in the style of grandstack-web (urql, typed operations, URL state), served by its own web server | copy grandstack-web wholesale for different data without saying what is shared |
| Running it all | Compose overlay files in the grandstack repository (compose.<setup>.yaml), used with compose.yaml | put a root compose.yaml in the new repository |
A new setup normally adds custom code in only two places: the part that is really new (for example a subgraph that talks to an external system, like the Wikipedia subgraph or the Aura subgraph), and the front end. The data layer, the gateway, the auth and the compose files come from the blocks.
When a block does not do what you need
Change the block, in its own repository, in a way that is generic and backward compatible, and use that. Do not work around it in the new repository.
Example: the Aura web UI needed the server to serve a different model, and to run a read-only copy beside a writable one. The answer was not a second server in the Aura repository. It was MODEL and READ_ONLY in grandstack-server, which any other setup can now use too, with the default (Movies) unchanged and tests and docs in that repository. The Aura repository kept only its model files.
Do this on a branch in the block’s repository, with its tests and its docs, and say in your change that another repository depends on it. Do not edit a block’s main.
What a new setup must do
Treat this as a checklist. Each item is how the existing setups (auth, agents, federation) already behave.
Compose, in the grandstack repository
- An overlay
compose.<name>.yaml, used withcompose.yaml, that builds the other repositories from sibling folders (../grandstack-<name>). - The standard ports (3000 web, 4000 GraphQL, 7474 and 7687 Neo4j). A setup that replaces another says so and replaces it on those ports rather than inventing new ones.
- Its own Neo4j volume if it uses a different model, so two setups never mix data.
- Images pinned to an exact version and a digest.
- A line in
.env.examplefor every new setting, a section indocs/configuration.md, the README’s “Run it with …” section,AGENTS.md,docs/agents.md,docs/roadmap.mdandllms.txt. - A setup in
scripts/integration.shand the nightlyintegration.yml, so it is run end to end with the others.
The repository itself
-
README.md,AGENTS.md, and the same docs set the other repositories have:docs/architecture.md,features.md,customising.md,recipes.md,testing.md(anddeploying.mdor similar if it has a deployment story), with diagrams indocs/diagrams/that carry a numbered legend.npm run docs:checkpasses (the link and diagram checker is copied fromgrandstack-web). - The two-line copyright header on every code file (
node ../grandstack/scripts/add-headers.mjs --check), andLICENSEandNOTICE(Apache 2.0, like every GRANDstack repository). - Exact-pinned dependencies, and the pins that must hold (
graphql16.x,@apollo/subgraph2.14.4). - The release workflows (
release.yml,release-cut.yml,dependency-review.yml,dependabot.yml), calling the shared workflows in the organisation’s.githubrepository. Do not make tags or bump versions by hand. - An entry in
grand-stack.github.io’sdocs-manifest.json, so its docs reach the website, and a row indocs/versioning-and-releases.mdanddocs/releasing.mdin thegrandstackrepository.
Safety, because these blocks run beside each other
- Say plainly what the setup can change and what it exposes, and bind to loopback by default if it can do harm without a sign-in.
- Never run
docker compose down -vunder the default project name beside a stack you want to keep: the merged files include the other setups’ data volumes. Use a project name of your own when testing.
Warning signs of a silo
If you are about to do any of these, stop and ask what block already does it:
- copying a file from
grandstack-server,grandstack-weborgrandstack-federationinto a new repository; - a
Dockerfilethat rebuilds the server or the gateway; - a
compose.yamlat the root of a repository other thangrandstack; - a port other than the standard ones for a role that already has one;
- a new sign-in, token or secret scheme next to
grandstack-auth; - documentation in a shape the other repositories do not use;
- a repository that cannot be started by adding one file to
grandstack’s compose command.
If a block really cannot serve the need, write down why in the new repository’s docs/architecture.md, and propose the change to the block rather than going around it.
Worked example: the Aura web UI
grandstack-web-aura is the first setup restructured onto the blocks. The first version had its own store server, its own gateway image and its own compose files. It was rebuilt on the blocks: the store is grandstack-server with MODEL=aura (read-only and writable), the gateway is grandstack-federation’s image with its own config files, and the compose files are compose.aura.yaml here. What stayed in its repository is what is new: the graph model, the Aura subgraph, a fake Aura for tests, the web app, and an optional TLS and sign-in edge. Its architecture page shows the result.
Next: architecture, configuration, agent guide, build your own app.
Source: grandstack/docs/building-on-grandstack.md (this page is a copy; edit it in the repository)