# GRAPH TYPE — Schema Enforcement DDL

> **PREVIEW feature — Neo4j 2026.02+**  
> Enterprise Edition, Infinigraph Edition, all Aura tiers.  
> Syntax may change before GA. Not supported for production use.  
> Feedback: graphtype@neo4j.com

GRAPH TYPE consolidates what previously required dozens of individual `CREATE CONSTRAINT` / `CREATE INDEX` statements into a single declarative schema definition. It operates on an **open model**: validation applies only to defined elements; extra labels and properties on nodes/relationships are still allowed.

Underlying constraints generated by GRAPH TYPE are visible via `SHOW CONSTRAINTS`.

---

## Lifecycle Commands

| Command | Purpose |
|---|---|
| `SHOW CURRENT GRAPH TYPE` | Display the full enforced schema |
| `ALTER CURRENT GRAPH TYPE SET { … }` | Replace/initialise the graph type (full redeclaration required) |
| `EXTEND GRAPH TYPE WITH { … }` | Add new elements without touching existing ones |
| `DROP GRAPH TYPE ELEMENTS { … }` | Remove schema enforcement; data is preserved |

---

## Syntax

### Define or replace the full schema

```cypher
CYPHER 25
ALTER CURRENT GRAPH TYPE SET {
  (person:Person {
    id       :: INTEGER NOT NULL,
    name     :: STRING  NOT NULL,
    born     :: INTEGER
  }) REQUIRE person.id IS KEY,

  (movie:Movie {
    movieId  :: STRING NOT NULL,
    title    :: STRING NOT NULL,
    released :: INTEGER
  }) REQUIRE movie.movieId IS KEY,

  // Label implication: every Crew node must also be a Person
  (crew:Crew => :Person),

  // Relationship type with enforced source and target node types
  (:Person)-[:ACTED_IN { roles :: LIST<STRING> }]->(:Movie),
  (:Person)-[:DIRECTED]->(:Movie),
  (:Person)-[:KNOWS { since :: DATE }]->(:Person)
}
```

### Extend incrementally

```cypher
CYPHER 25
EXTEND GRAPH TYPE WITH {
  (producer:Producer {
    name :: STRING NOT NULL
  }) REQUIRE producer.name IS UNIQUE,

  (:Producer)-[:PRODUCED]->(:Movie)
}
```

### Drop specific elements

```cypher
CYPHER 25
DROP GRAPH TYPE ELEMENTS {
  (:Producer)-[:PRODUCED]->(:Movie)
}
```

### Inspect current schema

```cypher
CYPHER 25
SHOW CURRENT GRAPH TYPE
```

---

## Property Types

| Type keyword | Notes |
|---|---|
| `STRING` | UTF-8 string |
| `INTEGER` | 64-bit signed integer |
| `FLOAT` | 64-bit float |
| `BOOLEAN` | true / false |
| `DATE` | Calendar date |
| `ZONED DATETIME` | Datetime with timezone |
| `LOCAL DATETIME` | Datetime without timezone |
| `DURATION` | ISO 8601 duration |
| `POINT` | Spatial point |
| `LIST<T>` | Homogeneous list (e.g. `LIST<STRING>`) |

Append `NOT NULL` to prohibit null values: `name :: STRING NOT NULL`

---

## Constraints Within GRAPH TYPE

| Syntax | Equivalent standalone constraint |
|---|---|
| `REQUIRE node.prop IS KEY` | `CREATE CONSTRAINT … REQUIRE n.prop IS NODE KEY` |
| `REQUIRE node.prop IS UNIQUE` | `CREATE CONSTRAINT … REQUIRE n.prop IS UNIQUE` |
| `prop :: TYPE NOT NULL` (inside node def) | `CREATE CONSTRAINT … REQUIRE n.prop IS NOT NULL` |

---

## Label Implications

```cypher
(crew:Crew => :Person)          // every :Crew node must also have :Person label
(admin:Admin => :Person:Staff)  // multiple implied labels
```

The implication is enforced on write — Neo4j rejects or auto-adds the implied label depending on configuration.

---

## Relationship Type Enforcement

Specifying source and target node types constrains which nodes may participate:

```cypher
(:Person)-[:KNOWS { since :: DATE }]->(:Person)
```

Attempting to create a `:KNOWS` relationship from a `:Movie` to a `:Person` will be rejected.

---

## When to Use GRAPH TYPE vs Individual Constraints

| Scenario | Recommendation |
|---|---|
| Greenfield project on 2026.02+, Enterprise/Aura | Use GRAPH TYPE — single source of truth for the schema |
| Existing database with many constraints already | Migrate incrementally with `EXTEND GRAPH TYPE WITH` |
| Neo4j < 2026.02 or Community Edition | Use `CREATE CONSTRAINT IF NOT EXISTS` per property |
| Production workload requiring stability | Wait for GA — PREVIEW syntax may change |

---

## Fallback (pre-2026.02)

```cypher
CREATE CONSTRAINT IF NOT EXISTS FOR (n:Person)  REQUIRE n.id      IS NODE KEY;
CREATE CONSTRAINT IF NOT EXISTS FOR (n:Movie)   REQUIRE n.movieId IS UNIQUE;
CREATE CONSTRAINT IF NOT EXISTS FOR (n:Person)  REQUIRE n.name    IS NOT NULL;
```

---

## References

- Docs: `https://neo4j.com/docs/cypher-manual/current/schema/graph-types/`
- Blog: `https://neo4j.com/blog/developer/graph-type-schema-enforcement-made-easy-preview/`
