Repository navigation
Service Neo4j
Neo4j provides graph database capabilities for Atlas, enabling relationship modeling and graph-based queries.
The Neo4j service provides:
- Graph database for storing and querying relationships
- Web-based browser interface for data visualization
- Cypher query language support
- Orchestrated offline system/application dumps and authenticated restore staging
NEO4J_GRAPH_DB_SOURCE |
Behavior | Browser / HTTP | Bolt |
|---|---|---|---|
container (default) |
Runs the Atlas-managed container. |
http://localhost:${GRAPH_DB_DASHBOARD_PORT} (default 63024) |
bolt://localhost:${GRAPH_DB_PORT} (default 63023) |
localhost |
Uses an existing host Neo4j; Atlas does not start the container. |
http://localhost:${NEO4J_LOCALHOST_HTTP_PORT} (default 7474) |
bolt://localhost:${NEO4J_LOCALHOST_BOLT_PORT} (default 7687) |
disabled |
Disables Neo4j and its routes. | unavailable | unavailable |
After running ./start.sh --setup-hosts, the Kong browser alias is http://graph.localhost:${KONG_HTTP_PORT} whenever the selected Neo4j source is enabled.
In container mode, the Browser pre-fills the in-network address neo4j://neo4j-graph-db:7687. From the host, change it to bolt://localhost:${GRAPH_DB_PORT}.
-
Username:
${GRAPH_DB_USER}(default:neo4j) -
Password:
${GRAPH_DB_PASSWORD}(from .env file)
These commands and paths apply only to NEO4J_GRAPH_DB_SOURCE=container. In localhost mode, use the backup and restore procedures of the host-managed Neo4j installation. Neo4j Community has no online dump, and the server is the container's main process. Every dump or load therefore runs against the stopped database volume. At startup, an empty neo4j database is restored automatically from the newest legacy snapshot. Atlas never schedules backups.
Run the docker compose commands from the repository root. If the checkout directory name is not PROJECT_NAME (default atlas), add -p "$PROJECT_NAME" to each command.
To manually create a graph database backup:
# Legacy single-database dump into /snapshot (database offline for the duration)
docker compose stop neo4j-graph-db
docker compose run --rm --no-deps --entrypoint /usr/local/bin/backup.sh neo4j-graph-db
docker compose start neo4j-graph-dbbackup.sh refuses to run (exit 75) inside the running container: stopping the server there stops the container before the dump starts.
Legacy dumps go to the ${PROJECT_NAME}-neo4j-backups volume at /snapshot. Checkouts that ran Neo4j before this volume existed may still hold dumps in services/neo4j/build/snapshot/. Atlas does not move or delete them. Check a dump's origin and Neo4j version before you load it by hand.
For coordinated backups, use services/backup/run-consistent-backup.sh. It dumps system and neo4j with the exact 5.26.31 image and writes signed metadata with the other database artifacts. It leaves Neo4j running or stopped, as it found it.
To restore from a previous backup:
# Load the newest /snapshot/backup_*.dump (database offline for the duration)
docker compose stop neo4j-graph-db
docker compose run --rm --no-deps --entrypoint /usr/local/bin/restore.sh neo4j-graph-db
docker compose start neo4j-graph-dbFor coordinated restores of the signed system + neo4j artifacts, use services/backup/run-database-restore.sh (see the backup service README).
- Automatic restoration at startup is enabled by default
- When the container starts with an empty
neo4jdatabase (a fresh data volume), it restores the latest/snapshot/backup_*.dumpif one exists../stop.sh --coldalso removes the snapshot volume, so nothing is left to restore after it; copy dumps you want to keep out first - A failed load (automatic or
restore.sh) leaves/data/.atlas-restore-incomplete. The next start then retries the load with--overwrite-destination. If nobackup_*.dumpis left, the container does not start: add a dump or delete the marker - A populated database is never overwritten at startup; to roll a live database back to a snapshot, use the offline
restore.sh(§4.2) - To turn off automatic restore, delete the
auto_restore.shCOPYand itsRUN chmodfrombuild/Dockerfile, then rebuild. The entrypoint then logs that automatic restore is disabled and starts normally
- Backups are full offline dumps (
neo4j-admin database dump). Restart the service yourself withdocker compose start. - Coordinated backups write
/snapshot/<timestamp>/neo4j.dump. Automatic restore ignores them.
With NEO4J_GRAPH_DB_SOURCE=container, Neo4j data is stored in Docker named volumes. In localhost mode, the host installation owns persistence:
-
Volume Name:
atlas-graph-db-data(from${PROJECT_NAME}-graph-db-data) -
Mount Point:
/data(inside container) -
Backup Location:
/snapshot(named-volume mount) -
Backup Volume:
${PROJECT_NAME}-neo4j-backups
Key environment variables for Neo4j:
# Authentication
GRAPH_DB_USER=neo4j
GRAPH_DB_PASSWORD=your_password
GRAPH_DB_AUTH=neo4j/your_password # Combined form consumed by the Neo4j container as NEO4J_AUTH
# Port Configuration
GRAPH_DB_PORT=63023 # Bolt protocol (mapped to 7687 inside the container)
GRAPH_DB_DASHBOARD_PORT=63024 # Browser interface and HTTP API (mapped to 7474)
# Container resources
NEO4J_MEMORY_LIMIT=2g # Compose memory limit for the container
NEO4J_CPU_LIMIT=1.5 # Compose CPU limit for the containerThe compose fragment loads APOC core (NEO4J_PLUGINS=["apoc"], from the image's labs/ jar, no download) and allows apoc.*. LLM Graph Builder needs it. The container accepts only the neo4j admin user, so GRAPH_DB_USER matters only in localhost mode.
Set PROJECT_NAME in your shell to the value in .env (default atlas). The command reads the credentials from the container's NEO4J_AUTH, so the password does not appear in a process argument list.
export PROJECT_NAME=atlas
docker exec -it ${PROJECT_NAME}-neo4j-graph-db sh -c \
'NEO4J_USERNAME="${NEO4J_AUTH%%/*}" NEO4J_PASSWORD="${NEO4J_AUTH#*/}" cypher-shell'Sample queries:
MATCH (n) RETURN count(n); // Count all nodes
MATCH (n) DETACH DELETE n; // Clear all data (use with caution)Export NEO4J_GRAPH_DB_SOURCE, GRAPH_DB_PASSWORD and any username or port overrides from .env into your shell before running this example. Container mode uses neo4j; localhost mode uses GRAPH_DB_USER (default neo4j).
import os
from neo4j import GraphDatabase
source = os.getenv("NEO4J_GRAPH_DB_SOURCE", "container")
username = (
os.getenv("GRAPH_DB_USER", "neo4j")
if source == "localhost"
else "neo4j"
)
bolt_port = (
os.getenv("NEO4J_LOCALHOST_BOLT_PORT", "7687")
if source == "localhost"
else os.getenv("GRAPH_DB_PORT", "63023")
)
driver = GraphDatabase.driver(
f"bolt://localhost:{bolt_port}",
auth=(username, os.environ["GRAPH_DB_PASSWORD"])
)
with driver.session() as session:
result = session.run("MATCH (n) RETURN count(n) as node_count")
print(result.single()["node_count"])
driver.close()// Create nodes
CREATE (:Person {name: 'Alice', age: 30}), (:Person {name: 'Bob', age: 25});
// Create a relationship
MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
CREATE (a)-[:KNOWS]->(b);
// Query relationships
MATCH (p:Person)-[:KNOWS]->(friend:Person)
RETURN p.name, friend.name;When LIGHTRAG_SOURCE != disabled AND NEO4J_GRAPH_DB_SOURCE != disabled, lightrag-init provisions the lightrag_entity_id range index on `base` nodes (migrate-neo4j.cypher). LightRAG writes the extracted KG (entities + relations) to Neo4j. Browse at graph.localhost:${KONG_HTTP_PORT}.
The backend declares a disabled Graphiti temporal graph memory experiment with GRAPHITI_ENABLED=false. No graphiti service, init companion, port, Kong alias, SOURCE value, or setup-wizard step exists yet; Neo4j remains the shared graph database container. Graphiti episodes written by the backend must use the group_id shape atlas:<project>:backend:<namespace>:user:<uuid>. This keeps Graphiti data apart from LightRAG, LLM Graph Builder, Hermes, OpenClaw and ad-hoc Cypher users.
Current Bolt clients are LightRAG (§8), LLM Graph Builder, JupyterHub, mcp-servers and the backup orchestrator (§15.2). Airflow seeds a neo4j_default Connection, and only operator-authored DAGs use it. The Backend receives NEO4J_* for planned graph endpoints but opens no Bolt connection (see docs/maintenance/integration-claims-ledger.md). n8n has no Neo4j wiring yet (§15.4).
NEO4J_MEMORY_LIMIT (default 2g) caps the container.
Without overrides, the image's memory defaults apply.
Atlas does not forward NEO4J_server_memory_* settings from .env.
To pin these settings, add them to the service's environment: through a Compose override:
services:
neo4j-graph-db:
environment:
NEO4J_server_memory_heap_initial__size: 512M
NEO4J_server_memory_heap_max__size: 512M
NEO4J_server_memory_pagecache_size: 512MThis example allocates 512 MiB each to heap and page cache. With the default 2 GiB cap, 1 GiB remains for native allocations and JVM overhead. Measure your workload before using these values in production. See Neo4j's memory guidance.
- Use indexes for frequently queried properties
- Limit result sets with
LIMITclause - Use
EXPLAINandPROFILEto analyze query performance - Consider graph data modeling best practices
# Check container status
docker logs ${PROJECT_NAME}-neo4j-graph-db -f
# Test HTTP endpoint
curl http://localhost:${GRAPH_DB_DASHBOARD_PORT}/
# Check Bolt connection (credentials from the container's NEO4J_AUTH)
docker exec ${PROJECT_NAME}-neo4j-graph-db sh -c \
'NEO4J_USERNAME="${NEO4J_AUTH%%/*}" NEO4J_PASSWORD="${NEO4J_AUTH#*/}" cypher-shell "RETURN 1 AS ok"'// Get database info
CALL db.info()
// Get node and relationship counts
MATCH (n) RETURN labels(n), count(n) ORDER BY count(n) DESC
// Check indexes
SHOW INDEXES// Remove all data (use with extreme caution)
MATCH (n) DETACH DELETE n
// Remove specific node types
MATCH (p:Person) DETACH DELETE p
Support tier: experimental — Capability contract declared; no cited cold-start, workflow, or upgrade qualification run yet (evidence at v0.1.0).
| Capability | Status | Verification | Notes |
|---|---|---|---|
| Container and host graph storage | supported | tested | Atlas supports a persistent Neo4j container or an operator-run localhost endpoint and wires Bolt consumers through the selected source. |
| Snapshot backup and restore | supported | tested | The backup orchestrator records whether Neo4j Community 5.26.31 is running and stops it for bounded system and neo4j database dumps. It restores the prior running state on success or failure, and provides an authenticated offline load path. |
| Production access isolation | partial | documented | Password authentication is configured, but direct Bolt and Browser ports are plaintext and Atlas does not provision separate least-privilege service roles. |
- Container won't start: check memory allocation and port conflicts.
-
Authentication failures: check
GRAPH_DB_PASSWORDandGRAPH_DB_AUTHin.env. Before the Neo4j data volume exists, each start setsGRAPH_DB_AUTHtoGRAPH_DB_USER/GRAPH_DB_PASSWORD. After that, Neo4j keeps its first-boot password, and a mismatch only prints a warning. To fix it, runALTER CURRENT USER SET PASSWORD ...incypher-shell, then set both values to match. - Connection refused: check that a firewall does not block the ports.
-
Out of memory errors: raise
NEO4J_MEMORY_LIMIT, or pin heap and page cache with a Compose override (§10.1).
# View detailed logs
docker logs ${PROJECT_NAME}-neo4j-graph-db --tail=100 -f
# Check resource usage
docker stats ${PROJECT_NAME}-neo4j-graph-db
# Verify configuration
docker exec ${PROJECT_NAME}-neo4j-graph-db cat /var/lib/neo4j/conf/neo4j.confIf the database is corrupted, restore the newest legacy snapshot offline with the §4.2 commands. Coordinated signed backups restore with services/backup/run-database-restore.sh.
If the newest backup is corrupted, reinitialize the database. This deletes all graph data. Automatic restore loads the newest /snapshot/backup_*.dump into any empty database, so rename the corrupted dump first. If an older backup_*.dump remains, the new database loads that one; rename every dump to start empty.
# 1. List the dumps.
docker compose run --rm --no-deps --entrypoint ls neo4j-graph-db -l /snapshot
# 2. Rename the corrupted dump so automatic restore skips it.
docker compose run --rm --no-deps --entrypoint mv neo4j-graph-db \
/snapshot/backup_<timestamp>.dump /snapshot/corrupt_<timestamp>.dump
# 3. Remove the container, then the data volume (Docker refuses while a container uses it).
docker compose rm -sf neo4j-graph-db
docker volume rm ${PROJECT_NAME}-graph-db-data
# 4. Start Neo4j on a new, empty volume.
docker compose up -d neo4j-graph-dbFor more troubleshooting help, see the troubleshooting guide.
No upstream calls.
Rows marked planned are documented or intended, not wired yet.
| Service | Category | Status |
|---|---|---|
| backup | infra | current |
| kong | infra | current |
| airflow | agents | optional: an operator-authored DAG; airflow-init only seeds the Connection |
| lightrag | agents | current |
| mcp-servers | agents | current |
| backend | apps | planned |
| jupyterhub | apps | current |
| llm-graph-builder | apps | current |

Open the full-size diagram for a full-screen view.
-
neo4j ↔ n8n — Why: unlocks no-code graph automation (entity sync, alerting on graph patterns, hydrating workflows from Cypher). n8n
2.28.2has no built-in Neo4j node. Mechanism: an HTTP Request node callshttp://neo4j-graph-db:7474/db/neo4j/tx/commitasneo4j/${GRAPH_DB_PASSWORD}. A community Neo4j node can usebolt://neo4j-graph-db:7687instead. AddNEO4J_URItoservices/n8n/compose.ymland a credential seed in n8n init. Effort: small. Confidence: medium. -
neo4j ↔ hermes — Why: persistent agent memory + entity/relation recall across sessions; Hermes skills write structured episodic memory as a graph and traverse it for context. Mechanism: Hermes custom skill via Bolt at
bolt://neo4j-graph-db:7687using the official neo4j Python driver;GRAPH_DB_USER/GRAPH_DB_PASSWORDfrom.env. Effort: medium. Confidence: medium. -
neo4j ↔ weaviate — Why: GraphRAG patterns — Weaviate finds semantically similar chunks, Neo4j expands the neighbourhood (entities, citations, relationships) for grounded answers. Mechanism: backend orchestrator: Weaviate
nearText→ take payloadentity_ids→ CypherMATCH (e)-[*1..2]-(n) RETURN n. Effort: medium. Confidence: medium. -
neo4j ↔ doc-processor — Why: Docling extracts structured document elements (sections, tables, references); persisting them as a graph turns the doc corpus into a navigable knowledge graph. Mechanism: backend route or n8n flow: docling JSON → LiteLLM entity/relation extractor → Cypher
MERGEover Bolt. Effort: medium. Confidence: medium. -
neo4j ↔ local-deep-researcher — Why: LDR lists neo4j as optional in
runtime_depsbut no concrete wiring exists; research runs naturally produce claim/source/entity graphs that benefit later sessions. Mechanism: LDR LangGraph node emitting Cypher on each research step viabolt://neo4j-graph-db:7687. Effort: small. Confidence: medium.
-
Graphiti (Zep) (
docs/research/candidates/graphiti.md) — Headline: temporal knowledge-graph framework for agent memory, built on Neo4j. Wires into: hermes, backend, n8n, local-deep-researcher. -
NeoDash (
docs/research/candidates/neodash.md) — Headline: low-code Cypher dashboards over the existing Neo4j instance, no extra database. Wires into: kong (route atdash.localhost), backend.
- Native vector index (HNSW) — Why pursue: Neo4j 5 ships an HNSW vector index. Embeddings could live on graph nodes, and one query could combine ANN search with graph traversal. Effort: small.
-
GenAI plugin (
genai.vector.encode*) — Why pursue: embed text directly inside Cypher via OpenAI/Vertex/Bedrock — wire it to LiteLLM and ingestion becomes one query. Effort: small. -
APOC extended — Why pursue: APOC core is loaded (
NEO4J_PLUGINS=["apoc"]from the image'slabs/jar); the extended library would add more JSON/HTTP, import and LLM procedures. Effort: small. - Neosemantics (n10s) — Why pursue: RDF/ontology import/export bridges Neo4j with external semantic-web sources (Wikidata, schema.org). Effort: medium.
-
Read-only role for LLM-generated Cypher — Why pursue: safe execution of model-authored queries from open-webui/hermes; mitigates prompt-injection-to-
DETACH DELETE. Effort: small.
Atlas documentation.
- 1. Overview
- 2. Quick Start
- 3. Core Concepts
- 4. Tracks
-
5. Services
- 5.1. Service Catalog
-
5.2. Service Guides
- 5.2.1. airflow
- 5.2.2. asset-baker
- 5.2.3. asset-worker
- 5.2.4. backend
- 5.2.5. backup
- 5.2.6. blender-mcp
- 5.2.7. celery
- 5.2.8. chatterbox
- 5.2.9. cloud-providers
- 5.2.10. cloudflared
- 5.2.11. comfyui
- 5.2.12. crawl4ai
- 5.2.13. doc-processor
- 5.2.14. docling
- 5.2.15. docling-lightrag-adapter
- 5.2.16. fal
- 5.2.17. globals
- 5.2.18. grafana
- 5.2.19. hermes
- 5.2.20. iceberg-rest
- 5.2.21. jenkins
- 5.2.22. jupyterhub
- 5.2.23. kong
- 5.2.24. label-studio
- 5.2.25. langfuse
- 5.2.26. lightrag
- 5.2.27. litellm
- 5.2.28. llm-graph-builder
- 5.2.29. local-deep-researcher
- 5.2.30. loki
- 5.2.31. mcp-servers
- 5.2.32. minio
- 5.2.33. mlflow
- 5.2.34. multi2vec-clip
- 5.2.35. n8n
- 5.2.36. neo4j
- 5.2.37. ollama
- 5.2.38. open-webui
- 5.2.39. openclaw
- 5.2.40. otel-collector
- 5.2.41. parakeet
- 5.2.42. prometheus
- 5.2.43. ray
- 5.2.44. redis
- 5.2.45. redpanda
- 5.2.46. searxng
- 5.2.47. spark
- 5.2.48. speaches
- 5.2.49. stt-provider
- 5.2.50. supabase
- 5.2.51. supavisor
- 5.2.52. tei-reranker
- 5.2.53. tempo
- 5.2.54. tika
- 5.2.55. trino
- 5.2.56. trueforge
- 5.2.57. tts-provider
- 5.2.58. verba
- 5.2.59. vllm-metal
- 5.2.60. weaviate
- 5.2.61. zeppelin
- 5.3. Provider And Extension Guides
- 6. Configuration
- 7. Operations
- 8. Architecture
- 9. Development
- 10. Reference