> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/getzep/graphiti/llms.txt
> Use this file to discover all available pages before exploring further.

# Nodes and Edges

> Understanding the graph schema: entity nodes, episodic nodes, communities, and their relationships

## Graph Schema Overview

Graphiti's knowledge graph is composed of **nodes** (entities, episodes, communities, sagas) and **edges** (relationships between nodes). Understanding this schema is essential for working with Graphiti effectively.

```mermaid theme={null}
graph LR
    E[EpisodicNode] -->|MENTIONS| EN[EntityNode]
    EN -->|RELATES_TO| EN2[EntityNode]
    C[CommunityNode] -->|HAS_MEMBER| EN
    S[SagaNode] -->|HAS_EPISODE| E
    E1[EpisodicNode] -->|NEXT_EPISODE| E2[EpisodicNode]
```

## Node Types

### EntityNode

Represents real-world entities extracted from episodes—people, organizations, concepts, events, etc.

```python theme={null}
class EntityNode(Node):
    uuid: str                          # Unique identifier
    name: str                          # Entity name
    name_embedding: list[float] | None # Vector embedding of the name
    summary: str                       # Aggregated summary from relationships
    labels: list[str]                  # Entity types (e.g., ["Person", "Employee"])
    attributes: dict[str, Any]         # Custom attributes
    group_id: str                      # Partition identifier
    created_at: datetime               # When first added to graph
```

#### Example

```python theme={null}
EntityNode(
    uuid="550e8400-e29b-41d4-a716-446655440000",
    name="Kamala Harris",
    labels=["Person", "Politician"],
    summary="Kamala Harris served as Attorney General of California from 2011-2017 and became Vice President in 2021.",
    attributes={
        "birth_year": 1964,
        "education": "Howard University, UC Hastings"
    },
    group_id="default",
    created_at=datetime(2024, 3, 15, tzinfo=timezone.utc)
)
```

#### Key Fields

**name**: The canonical name of the entity

* Graphiti deduplicates entities by name similarity
* Used for entity resolution across episodes

**name\_embedding**: Vector representation for semantic search

* Generated by your configured embedder (e.g., OpenAI, Voyage)
* Enables similarity-based entity retrieval

```python theme={null}
# Generate embedding
await entity_node.generate_name_embedding(embedder)
```

**summary**: Automatically generated from connected edges

* Aggregates facts from all EntityEdges connected to this node
* Updated as new information is added
* Useful for quick entity context

**labels**: Entity types for classification

* Can be a single type: `["Person"]`
* Or multiple types: `["Person", "Executive", "Founder"]`
* Used with custom entity types (see Custom Entity Types guide)

**attributes**: Flexible key-value properties

* Store domain-specific data
* Defined by custom entity type schemas
* Extracted by LLM during processing

```python theme={null}
# Custom entity type with attributes
from pydantic import BaseModel, Field

class Employee(BaseModel):
    department: str = Field(description="Department name")
    start_date: str = Field(description="Employment start date")
    role: str = Field(description="Job title")

entity_types = {"Employee": Employee}
```

#### Working with EntityNodes

```python theme={null}
# Get by UUID
node = await EntityNode.get_by_uuid(driver, uuid="...")

# Get by group IDs
nodes = await EntityNode.get_by_group_ids(
    driver,
    group_ids=["user_123"],
    limit=100
)

# Save a node
await node.save(driver)

# Delete a node (and connected edges)
await node.delete(driver)
```

### EpisodicNode

Stores raw input episodes with temporal metadata. See [Episodes](/concepts/episodes) for detailed information.

```python theme={null}
class EpisodicNode(Node):
    uuid: str
    name: str
    content: str                   # Raw episode data
    source: EpisodeType           # message | json | text
    source_description: str        # Metadata about the source
    valid_at: datetime            # When content occurred
    created_at: datetime          # When ingested
    entity_edges: list[str]       # UUIDs of extracted EntityEdges
    group_id: str
```

#### Example

```python theme={null}
EpisodicNode(
    uuid="660e8400-e29b-41d4-a716-446655440001",
    name="Customer Support Chat 2024-03-15",
    content="user: My order is delayed\nassistant: Let me check that",
    source=EpisodeType.message,
    source_description="support_ticket_5678",
    valid_at=datetime(2024, 3, 15, 10, 30, tzinfo=timezone.utc),
    created_at=datetime(2024, 3, 15, 10, 35, tzinfo=timezone.utc),
    entity_edges=["edge-uuid-1", "edge-uuid-2"],
    group_id="customer_123"
)
```

### CommunityNode

Represents clusters of related entities discovered through graph analysis. See [Communities](/concepts/communities) for details.

```python theme={null}
class CommunityNode(Node):
    uuid: str
    name: str                         # Auto-generated description
    name_embedding: list[float] | None
    summary: str                      # Aggregate summary of member entities
    group_id: str
    created_at: datetime
```

#### Example

```python theme={null}
CommunityNode(
    uuid="770e8400-e29b-41d4-a716-446655440002",
    name="California Political Leadership",
    summary="Community of political figures who have served in California government positions including Governor, Attorney General, and Lieutenant Governor.",
    group_id="default",
    created_at=datetime(2024, 3, 15, tzinfo=timezone.utc)
)
```

### SagaNode

Organizes sequences of related episodes (e.g., conversation threads, event timelines).

```python theme={null}
class SagaNode(Node):
    uuid: str
    name: str          # Saga identifier
    group_id: str
    created_at: datetime
```

#### Example

```python theme={null}
SagaNode(
    uuid="880e8400-e29b-41d4-a716-446655440003",
    name="customer_support_conversation_123",
    group_id="customer_456",
    created_at=datetime(2024, 3, 15, tzinfo=timezone.utc)
)
```

## Edge Types

### EntityEdge (RELATES\_TO)

Represents semantic relationships between entities, with temporal validity tracking.

```python theme={null}
class EntityEdge(Edge):
    uuid: str
    source_node_uuid: str         # Source EntityNode UUID
    target_node_uuid: str         # Target EntityNode UUID
    name: str                     # Relationship name
    fact: str                     # Natural language fact
    fact_embedding: list[float] | None
    episodes: list[str]           # Episode UUIDs that mention this edge
    group_id: str
    
    # Temporal fields
    created_at: datetime          # When edge was first created
    expired_at: datetime | None   # When edge was invalidated by new info
    valid_at: datetime | None     # When the fact became true
    invalid_at: datetime | None   # When the fact stopped being true
    
    # Custom attributes
    attributes: dict[str, Any]
```

#### Example

```python theme={null}
EntityEdge(
    uuid="990e8400-e29b-41d4-a716-446655440004",
    source_node_uuid="kamala-harris-uuid",
    target_node_uuid="california-ag-uuid",
    name="held_position",
    fact="Kamala Harris served as Attorney General of California from January 2011 to January 2017.",
    fact_embedding=[0.123, -0.456, ...],  # 1536-dim vector
    episodes=["episode-uuid-1", "episode-uuid-2"],
    group_id="default",
    created_at=datetime(2024, 3, 15, tzinfo=timezone.utc),
    expired_at=None,  # Still current in the graph
    valid_at=datetime(2011, 1, 3, tzinfo=timezone.utc),
    invalid_at=datetime(2017, 1, 3, tzinfo=timezone.utc),
    attributes={"position_type": "elected_official"}
)
```

#### Key Fields

**name**: The relationship type

* Examples: `"works_at"`, `"knows"`, `"located_in"`, `"married_to"`
* Can be customized with edge types (see Custom Edge Types guide)

**fact**: Human-readable description of the relationship

* Used for search and retrieval
* Embedded for semantic similarity

```python theme={null}
fact="Alice Chen joined Acme Corp as Senior Engineer in March 2024."
```

**fact\_embedding**: Vector representation for semantic search

* Generated from the `fact` text
* Enables similarity-based edge retrieval

**episodes**: Provenance tracking

* Lists all episodes that mentioned this relationship
* Enables tracing back to original sources

```python theme={null}
# Find episodes that mention an edge
episode_uuids = edge.episodes
episodes = await EpisodicNode.get_by_uuids(driver, episode_uuids)
```

**Temporal fields**: See [Temporal Model](/concepts/temporal-model)

* `valid_at`: When the fact became true in the real world
* `invalid_at`: When the fact stopped being true
* `created_at`: When Graphiti learned about it
* `expired_at`: When superseded by newer information

#### Working with EntityEdges

```python theme={null}
# Get by UUID
edge = await EntityEdge.get_by_uuid(driver, uuid="...")

# Get edges connected to a node
edges = await EntityEdge.get_by_node_uuid(driver, node_uuid="...")

# Get edges between two nodes
edges = await EntityEdge.get_between_nodes(
    driver,
    source_node_uuid="alice-uuid",
    target_node_uuid="acme-uuid"
)

# Save an edge
await edge.save(driver)

# Delete an edge
await edge.delete(driver)
```

### EpisodicEdge (MENTIONS)

Links episodes to the entities they mention.

```python theme={null}
class EpisodicEdge(Edge):
    uuid: str
    source_node_uuid: str  # EpisodicNode UUID
    target_node_uuid: str  # EntityNode UUID
    group_id: str
    created_at: datetime
```

#### Purpose

EpisodicEdges provide **provenance**—you can always trace which episodes mentioned which entities.

```python theme={null}
# Find all episodes that mention "Alice"
episodes = await EpisodicNode.get_by_entity_node_uuid(
    driver,
    entity_node_uuid=alice.uuid
)
```

### CommunityEdge (HAS\_MEMBER)

Links communities to their member entities.

```python theme={null}
class CommunityEdge(Edge):
    uuid: str
    source_node_uuid: str  # CommunityNode UUID
    target_node_uuid: str  # EntityNode UUID
    group_id: str
    created_at: datetime
```

#### Usage

```python theme={null}
# Find all entities in a community
records, _, _ = await driver.execute_query("""
    MATCH (c:Community {uuid: $community_uuid})-[:HAS_MEMBER]->(e:Entity)
    RETURN e
""", community_uuid=community.uuid)
```

### HasEpisodeEdge (HAS\_EPISODE)

Links sagas to their episodes.

```python theme={null}
class HasEpisodeEdge(Edge):
    uuid: str
    source_node_uuid: str  # SagaNode UUID
    target_node_uuid: str  # EpisodicNode UUID
    group_id: str
    created_at: datetime
```

### NextEpisodeEdge (NEXT\_EPISODE)

Chains episodes in chronological order within a saga.

```python theme={null}
class NextEpisodeEdge(Edge):
    uuid: str
    source_node_uuid: str  # Earlier EpisodicNode UUID
    target_node_uuid: str  # Later EpisodicNode UUID
    group_id: str
    created_at: datetime
```

#### Usage

```python theme={null}
# Traverse a conversation thread
records, _, _ = await driver.execute_query("""
    MATCH path = (start:Episodic)-[:NEXT_EPISODE*]->(end:Episodic)
    WHERE start.uuid = $start_uuid
    RETURN path
""", start_uuid=first_episode.uuid)
```

## Node and Edge Inheritance

All nodes and edges inherit from base classes:

```python theme={null}
class Node(BaseModel, ABC):
    uuid: str = Field(default_factory=lambda: str(uuid4()))
    name: str
    group_id: str
    labels: list[str] = Field(default_factory=list)
    created_at: datetime = Field(default_factory=lambda: utc_now())
    
    @abstractmethod
    async def save(self, driver: GraphDriver): ...
    async def delete(self, driver: GraphDriver): ...

class Edge(BaseModel, ABC):
    uuid: str = Field(default_factory=lambda: str(uuid4()))
    group_id: str
    source_node_uuid: str
    target_node_uuid: str
    created_at: datetime
    
    @abstractmethod
    async def save(self, driver: GraphDriver): ...
    async def delete(self, driver: GraphDriver): ...
```

This provides consistent interfaces for all graph elements.

## Graph Queries

### Finding Connected Information

```python theme={null}
# Get all relationships for an entity
edges = await EntityEdge.get_by_node_uuid(driver, node_uuid=alice.uuid)

# Find entities related to Alice
records, _, _ = await driver.execute_query("""
    MATCH (alice:Entity {uuid: $alice_uuid})-[:RELATES_TO]-(related:Entity)
    RETURN related
""", alice_uuid=alice.uuid)
```

### Traversing Multi-Hop Relationships

```python theme={null}
# Find entities within 2 hops
records, _, _ = await driver.execute_query("""
    MATCH (start:Entity {uuid: $start_uuid})-[:RELATES_TO*1..2]-(connected:Entity)
    RETURN DISTINCT connected
""", start_uuid=start_node.uuid)
```

### Temporal Queries

```python theme={null}
# Find facts valid at a specific time
records, _, _ = await driver.execute_query("""
    MATCH (n)-[e:RELATES_TO]->(m)
    WHERE e.valid_at <= $query_time
      AND (e.invalid_at > $query_time OR e.invalid_at IS NULL)
      AND e.expired_at IS NULL
    RETURN e
""", query_time=datetime(2023, 6, 1, tzinfo=timezone.utc))
```

## Embeddings

Graphiti generates vector embeddings for semantic search:

### Entity Name Embeddings

```python theme={null}
# Generate embedding for an entity
await entity_node.generate_name_embedding(embedder)
# Sets entity_node.name_embedding = [0.123, -0.456, ...]

# Batch generation for multiple entities
from graphiti_core.nodes import create_entity_node_embeddings

await create_entity_node_embeddings(embedder, entity_nodes)
```

### Edge Fact Embeddings

```python theme={null}
# Generate embedding for an edge
await entity_edge.generate_embedding(embedder)
# Sets entity_edge.fact_embedding = [0.234, -0.567, ...]

# Batch generation for multiple edges
from graphiti_core.edges import create_entity_edge_embeddings

await create_entity_edge_embeddings(embedder, entity_edges)
```

### Embedding Configuration

```python theme={null}
from graphiti_core.embedder.openai import OpenAIEmbedder, OpenAIEmbedderConfig

# Custom embedder
embedder = OpenAIEmbedder(
    config=OpenAIEmbedderConfig(
        embedding_model="text-embedding-3-large",
        embedding_dim=3072  # Dimension depends on model
    )
)

graphiti = Graphiti(uri, user, password, embedder=embedder)
```

## Database Backend Differences

Graphiti supports multiple graph databases with minor schema variations:

### Neo4j, FalkorDB, Neptune

```cypher theme={null}
-- EntityEdge as a relationship
MATCH (n:Entity)-[e:RELATES_TO]->(m:Entity)
RETURN e
```

### Kuzu

```cypher theme={null}
-- EntityEdge as an intermediate node
MATCH (n:Entity)-[:RELATES_TO]->(e:RelatesToNode_)-[:RELATES_TO]->(m:Entity)
RETURN e
```

<Info>
  Graphiti's driver abstraction handles these differences automatically. You don't need to write different queries for different backends.
</Info>

## Custom Attributes

Both EntityNodes and EntityEdges support custom attributes:

```python theme={null}
from pydantic import BaseModel, Field

# Define a custom entity type
class Person(BaseModel):
    age: int = Field(description="Person's age")
    occupation: str = Field(description="Job title")
    city: str = Field(description="Current city")

# Define a custom edge type
class WorksAt(BaseModel):
    start_date: str = Field(description="Employment start date")
    department: str = Field(description="Department name")

# Use in add_episode
result = await graphiti.add_episode(
    name="HR Data",
    episode_body="Alice Chen, 32, works as a Software Engineer in the Platform team. She joined on 2024-01-15 in San Francisco.",
    source=EpisodeType.text,
    reference_time=datetime.now(timezone.utc),
    entity_types={"Person": Person},
    edge_types={"WorksAt": WorksAt}
)

# Extracted EntityNode will have:
# attributes = {"age": 32, "occupation": "Software Engineer", "city": "San Francisco"}

# Extracted EntityEdge will have:
# attributes = {"start_date": "2024-01-15", "department": "Platform"}
```

## Group IDs and Multi-Tenancy

Every node and edge has a `group_id` field for partitioning:

```python theme={null}
# Add data to different groups
await graphiti.add_episode(
    name="User 1 Data",
    episode_body="Alice likes hiking.",
    group_id="user_1",
    reference_time=datetime.now(timezone.utc)
)

await graphiti.add_episode(
    name="User 2 Data",
    episode_body="Bob likes coding.",
    group_id="user_2",
    reference_time=datetime.now(timezone.utc)
)

# Search within a group
results = await graphiti.search(
    "What does the user like?",
    group_ids=["user_1"]  # Only searches user_1's data
)
```

## Schema Visualization

Here's the complete graph schema:

```mermaid theme={null}
graph TB
    subgraph "Episode Layer"
        S[SagaNode]
        E1[EpisodicNode]
        E2[EpisodicNode]
    end
    
    subgraph "Entity Layer"
        EN1[EntityNode]
        EN2[EntityNode]
        EN3[EntityNode]
    end
    
    subgraph "Community Layer"
        C[CommunityNode]
    end
    
    S -->|HAS_EPISODE| E1
    S -->|HAS_EPISODE| E2
    E1 -->|NEXT_EPISODE| E2
    E1 -->|MENTIONS| EN1
    E1 -->|MENTIONS| EN2
    E2 -->|MENTIONS| EN2
    E2 -->|MENTIONS| EN3
    EN1 -->|RELATES_TO| EN2
    EN2 -->|RELATES_TO| EN3
    C -->|HAS_MEMBER| EN1
    C -->|HAS_MEMBER| EN2
    C -->|HAS_MEMBER| EN3
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Communities" icon="users" href="/concepts/communities">
    Learn about community detection and clustering
  </Card>

  <Card title="Custom Types" icon="shapes" href="/guides/custom-types">
    Define custom entity and edge types
  </Card>

  <Card title="Search" icon="magnifying-glass" href="/guides/search">
    Query nodes and edges effectively
  </Card>

  <Card title="Temporal Model" icon="clock" href="/concepts/temporal-model">
    Understand temporal aspects of nodes and edges
  </Card>
</CardGroup>
