本文へ移動
cccskills
無料GitHub で公開

neo4j-best-practices

Neo4j best practices for Cypher query optimization, graph data modeling, indexing, and safe execution of LLM-generated Cypher

インストール方法を見る

含まれるファイル(1)

  • SKILL.md7.5 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Neo4j Best Practices

Query Optimization

PROFILE / EXPLAIN (CRITICAL)

  • Use EXPLAIN to validate a query plan without executing it — the mandatory pre-execution gate for any generated Cypher
  • Use PROFILE to see actual DB hits, rows, and time per operator when a query is already known-safe
  • Watch for NodeByLabelScan/AllNodesScan where an index seek (NodeIndexSeek) was expected — usually a missing index or non-sargable predicate
  • Watch for CartesianProduct — almost always an unintended disconnected pattern; add a relationship or WHERE join condition
  • Watch for Eager operators — they materialize the whole intermediate result and block streaming; common with MERGE combined with earlier writes/reads in the same query

Query Shape (CRITICAL)

  • Filter as early as possible — put label and property predicates on the first MATCH, not after a chain of traversals
  • Use WHERE on indexed properties, not on computed/derived expressions (kills index usage)
  • Prefer directed, typed relationship patterns (-[:FOLLOWS]->) over untyped/undirected ones — undirected patterns force the planner to consider both directions
  • Bound variable-length paths ([:LINKS*1..3]) — unbounded (*) traversals on non-trivial graphs risk combinatorial blowup
  • Use LIMIT with ORDER BY early in multi-part queries (WITH ... LIMIT ...) to avoid sorting the full result set

Data Modeling

Node Labels vs Properties (CRITICAL)

  • A value becomes a label when it is used to filter/scan a large subset of the graph, participates in relationships, or needs its own indexes/constraints
  • A value stays a property when it is descriptive, high-cardinality, or never independently queried
  • Avoid modeling everything as generic Entity nodes with a type property — this collapses the type system into runtime string comparisons and defeats label-based indexing

Relationships (CRITICAL)

  • Relationship type encodes the semantic verb (:PURCHASED, :AUTHORED) — do not reuse one generic relationship type (:RELATED_TO) with a property to distinguish meaning
  • Choose a single consistent direction per relationship type based on the dominant query direction; query the reverse direction with <-[]- rather than modeling both directions
  • Avoid supernodes: a node with relationship fan-out in the tens of thousands (e.g., a "Country" node connected to every citizen) degrades traversal and lock behavior — consider intermediate/bucket nodes

Time and History

  • Model temporal facts as relationship properties (since, until) or intermediate event nodes when a fact changes over time, rather than overwriting node properties and losing history

Indexes and Constraints

Index Types (CRITICAL)

  • Range index: default for equality/range lookups on scalar properties — create for every property used in WHERE/MERGE matching at scale
  • Text index: substring/CONTAINS/ENDS WITH queries on string properties (range indexes only accelerate prefix/exact matches)
  • Point index: spatial point() property queries
  • Full-text index: relevance-ranked, tokenized text search (db.index.fulltext.queryNodes)

Constraints (CRITICAL)

  • Uniqueness constraint on every natural key used for MERGE — without it, concurrent MERGE can create duplicate nodes
  • Property-existence constraint (Enterprise) for properties the application always expects to be present
  • Constraints implicitly create a backing index — do not create a redundant explicit index on the same property

Go Driver (neo4j-go-driver v5)

Session and Transaction Management (CRITICAL)

  • One neo4j.DriverWithContext per process; open short-lived Sessions per unit of work, never share a session across goroutines
  • Use ExecuteRead/ExecuteWrite (managed transactions) instead of manual BeginTransaction — they provide automatic retry on transient errors (leader switch, deadlock)
  • Never build Cypher via string concatenation/fmt.Sprintf with user data — always pass a map[string]any of parameters as the second argument to Run/ExecuteRead
  • Set explicit context timeouts (context.WithTimeout) on every session/transaction to bound worst-case latency
  • Configure neo4j.Config.MaxConnectionPoolSize and ConnectionAcquisitionTimeout for the expected concurrency; do not leave pool size unbounded

Result Handling

  • Prefer result.Collect(ctx) for small bounded results, streaming iteration (result.Next(ctx)) for large results — avoid materializing unbounded result sets in memory

Safe Execution of LLM-Generated Cypher (CRITICAL)

This is the primary safety layer for any natural-language-to-Cypher feature.

  1. Read-only enforcement: execute generated Cypher only through a session/user restricted to the reader role (or neo4j.AccessModeRead on the transaction), never a writer-capable session
  2. Mandatory parameterization: reject any generated query that embeds literal values instead of $param placeholders — this also defends against Cypher injection from upstream LLM output
  3. Pre-execution EXPLAIN gate: run EXPLAIN <query> first; reject on syntax/semantic errors before touching real data, and inspect the plan for scan operators that indicate a missing index or runaway cardinality
  4. Destructive-clause blocklist: statically reject queries containing DETACH DELETE, DELETE, REMOVE, SET, CREATE, MERGE, CALL { ... } IN TRANSACTIONS, LOAD CSV, or any apoc.* write/refactor procedure — a read-only-role session is defense-in-depth, not a substitute for this check
  5. Query complexity bounds: cap unbounded variable-length paths, enforce a default LIMIT, and set a server-side query timeout for LLM-originated queries specifically (dbms.transaction.timeout or a per-query neo4j.WithTxTimeout)
  6. No local text2cypher models: this project uses remote LLM APIs only — do not introduce Neo4j's locally-hosted text2cypher fine-tuned models or any component requiring local inference weights

PostgreSQL-as-Source-of-Truth Pattern

  • Treat Neo4j as a rebuildable projection of PostgreSQL, not an independent system of record — every node/relationship should be traceable back to a Postgres row
  • Prefer full-rebuild-from-Postgres for correctness-critical launches; move to incremental sync (CDC, outbox pattern, or scheduled diff) only once the projection shape has stabilized
  • Version the projection logic (mapping Postgres tables/columns to Cypher MERGE statements) alongside schema migrations so the graph can always be regenerated deterministically
  • Do not accept direct writes to Neo4j from application code paths that bypass the sync/rebuild pipeline — this breaks the rebuildability guarantee

References

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Pre-action boundary checking — validates agent tool calls against declared capabilities and task contracts

日本語の概要は準備中です。原文の説明を表示しています。

baekenough/second-brain152026年10月8日 更新

Auto-detect project context and optimize harness — deactivate unused agents/skills, suggest missing experts, generate project profile

日本語の概要は準備中です。原文の説明を表示しています。

baekenough/second-brain152026年10月8日 更新

Adversarial code review using attacker mindset — trust boundary, attack surface, business logic, and defense evaluation

日本語の概要は準備中です。原文の説明を表示しています。

baekenough/second-brain152026年10月8日 更新

Apache Airflow best practices for DAG authoring, testing, and production deployment

日本語の概要は準備中です。原文の説明を表示しています。

baekenough/second-brain152026年10月8日 更新

Alembic migration patterns for naming conventions, safety checks, expand-contract, env.py configuration, and CI integration

日本語の概要は準備中です。原文の説明を表示しています。

baekenough/second-brain152026年10月8日 更新

Pre-routing ambiguity analysis — scores request clarity and asks clarifying questions when needed (inspired by ouroboros)

日本語の概要は準備中です。原文の説明を表示しています。

baekenough/second-brain152026年10月8日 更新

baekenough のスキルをすべて見る

このスキルの問題を報告する