$npx -y skills add neo4j-contrib/neo4j-skills --skill neo4j-modeling-skillDesign, review, and refactor Neo4j graph data models. Use when choosing node
| 1 | ## When to Use |
| 2 | |
| 3 | - Designing graph model from scratch (domain → nodes, rels, props) |
| 4 | - Reviewing existing model for anti-patterns |
| 5 | - Deciding node vs property vs relationship vs label |
| 6 | - Migrating relational or document schema to graph |
| 7 | - Designing intermediate nodes for n-ary or complex relationships |
| 8 | - Detecting and mitigating supernode / high-fanout problems |
| 9 | - Choosing and creating constraints + indexes for a model |
| 10 | |
| 11 | ## When NOT to Use |
| 12 | |
| 13 | - **Writing or optimizing Cypher** → `neo4j-cypher-skill` |
| 14 | - **Spring Data Neo4j (@Node, @Relationship)** → `neo4j-spring-data-skill` |
| 15 | - **GraphQL type definitions** → `neo4j-graphql-skill` |
| 16 | - **Importing data (LOAD CSV, APOC import)** → `neo4j-import-skill` |
| 17 | |
| 18 | --- |
| 19 | |
| 20 | ## Inspect Before Designing |
| 21 | |
| 22 | On existing database, run first — never propose changes without current state: |
| 23 | |
| 24 | ```cypher |
| 25 | CALL db.schema.visualization() YIELD nodes, relationships RETURN nodes, relationships; |
| 26 | SHOW CONSTRAINTS YIELD name, type, labelsOrTypes, properties RETURN name, type, labelsOrTypes, properties; |
| 27 | SHOW INDEXES YIELD name, type, labelsOrTypes, state WHERE state = 'ONLINE' RETURN name, type, labelsOrTypes; |
| 28 | ``` |
| 29 | |
| 30 | If APOC available: |
| 31 | ```cypher |
| 32 | CALL apoc.meta.schema() YIELD value RETURN value; |
| 33 | ``` |
| 34 | |
| 35 | MCP tool map: |
| 36 | |
| 37 | | Operation | Tool | |
| 38 | |---|---| |
| 39 | | Inspect schema | `get-schema` | |
| 40 | | `SHOW CONSTRAINTS`, `SHOW INDEXES` | `read-cypher` | |
| 41 | | `CREATE CONSTRAINT ... IF NOT EXISTS` | `write-cypher` (show + confirm first) | |
| 42 | |
| 43 | --- |
| 44 | |
| 45 | ## Defaults — Apply to Every Model |
| 46 | |
| 47 | 1. Use-case first — list 5+ queries the model must answer before designing |
| 48 | 2. Nodes = entities (nouns) with identity; rels = connections (verbs) with direction |
| 49 | 3. Labels PascalCase; rel types SCREAMING_SNAKE_CASE; properties camelCase |
| 50 | 4. Every node type used in MERGE has a uniqueness constraint on its key property |
| 51 | 5. Add property type constraints (`REQUIRE n.prop IS :: STRING`) where the type is known — helps the query planner and catches bad writes early |
| 52 | 6. No generic labels (`:Entity`, `:Node`, `:Thing`); no generic rel types (`:RELATED_TO`, `:HAS`) |
| 53 | 7. Security labels (used for row-level access control) should start with a common prefix (e.g. `Sec`) so application code can reliably filter them out of the domain schema |
| 54 | 8. Rel direction encodes semantic meaning — not arbitrary |
| 55 | 9. Inspect schema before proposing any change on an existing database |
| 56 | 10. All constraint/index DDL uses `IF NOT EXISTS` — safe to rerun |
| 57 | 11. **On Neo4j 2026.02+ (Enterprise/Aura):** consider `ALTER CURRENT GRAPH TYPE SET { … }` or `EXTEND GRAPH TYPE WITH { … }` to declare the full model in one block instead of individual `CREATE CONSTRAINT` statements — see `neo4j-cypher-skill/references/graph-type.md`. **PREVIEW** — syntax may change before GA. |
| 58 | |
| 59 | --- |
| 60 | |
| 61 | ## Key Patterns |
| 62 | |
| 63 | ### Node vs Relationship vs Property — Decision Table |
| 64 | |
| 65 | | Question | Answer | Model as | |
| 66 | |---|---|---| |
| 67 | | Is it a thing with identity, queried as entry point? | Yes | Node | |
| 68 | | Is it a connection between two things with direction? | Yes | Relationship | |
| 69 | | Does the connection have its own properties or multiple targets? | Yes | Intermediate node | |
| 70 | | Is it a scalar always returned with its parent, never filtered alone? | Yes | Property on parent | |
| 71 | | Is it a category used for type-based filtering or path traversal? | Yes | Label (not a property) | |
| 72 | | Does the same attribute value repeat across many nodes (low cardinality)? | Yes | Label, not a property node | |
| 73 | | Is it a fact connecting >2 entities? | Yes | Intermediate node | |
| 74 | |
| 75 | ### Property vs Label — Decision Table |
| 76 | |
| 77 | | Use label when | Use property when | |
| 78 | |---|---| |
| 79 | | Values are few, fixed, used as traversal filters (`WHERE n:Active`) | Values are many, dynamic, or unique per node | |
| 80 | | You traverse by type (`MATCH (n:VIPCustomer)`) | You filter by value (`WHERE n.tier = 'vip'`) | |
| 81 | | Category drives index selection | Fine-grained value drives range scans | |
| 82 | | Example: `:Active`, `:Verified`, `:Premium` | Example: `status`, `score`, `email` | |
| 83 | |
| 84 | Rule: adding a label is cheap; scanning all `:Label` nodes is fast. Never model high-cardinality values as labels. |
| 85 | |
| 86 | --- |
| 87 | |
| 88 | ### Intermediate Node Pattern |
| 89 | |
| 90 | Use when a relationship needs its own properties, connects >2 entities, or is independently queryable. |
| 91 | |
| 92 | **Before (relationship wit |