# Getting Started
This guide walks you through the core operations: creating a database, adding
nodes and edges, querying the graph, updating data, and running a time-travel query.
By the end you'll have a working mental model of how AletheiaDB works day-to-day.
**Prerequisites:** Rust 1.92+ and AletheiaDB in your `Cargo.toml`. See [Installation](installation.md).
---
## 1. Create a Database
```rust
use aletheiadb::prelude::*;
fn main() -> Result<()> {
let db = AletheiaDB::new()?;
// db is ready to use
Ok(())
}
```
`AletheiaDB::new()` creates a **disk-backed** database in `./aletheiadb/wal`
(relative to the current working directory) with Group Commit durability. Data
survives process restart. For a different path, in-memory testing, or custom
durability settings, use `AletheiaDB::with_unified_config()` — see
[Persistence Guide](PERSISTENCE.md).
> **Note on leftover state**: If you run examples in the same directory repeatedly,
> you may see `InvalidTimeRange` errors from previous runs. Clear `./aletheiadb`
> between runs, or point each run at its own directory via `AletheiaDBConfig`.
---
## 2. Create Nodes
Nodes have a **label** (a type name) and **properties** (key/value pairs).
```rust
use aletheiadb::prelude::*;
let db = AletheiaDB::new()?;
let alice_id = db.create_node("Person", properties! {
"name" => "Alice",
"age" => 30i64,
})?;
let bob_id = db.create_node("Person", properties! {
"name" => "Bob",
"age" => 28i64,
})?;
println!("Alice: {:?}, Bob: {:?}", alice_id, bob_id);
```
`create_node` returns a `NodeId`. Hold onto it — you'll use it for edges and queries.
---
## 3. Create Edges
Edges connect two nodes with a **relationship type** and optional properties.
```rust
let edge_id = db.create_edge(alice_id, bob_id, "KNOWS", properties! {
"since" => 2023i64,
})?;
```
Edges are directed: this edge goes from Alice → Bob over the `KNOWS` relationship.
---
## 4. Read Nodes and Edges
```rust
// Read a single node
let alice = db.get_node(alice_id)?;
println!("Label: {}", alice.label); // "Person"
println!("Name: {:?}", alice.properties.get("name")); // Some("Alice")
// Read an edge
let edge = db.get_edge(edge_id)?;
println!("From: {:?}, To: {:?}", edge.source, edge.target);
// Traverse: get edge IDs for a specific relationship type, then fetch each edge
let edge_ids = db.get_outgoing_edges_with_label(alice_id, "KNOWS");
for eid in edge_ids {
let e = db.get_edge(eid)?;
println!("Alice knows node: {:?}", e.target);
}
```
---
## 5. Update Data
Use an explicit write transaction to update nodes or edges atomically.
```rust
"age" => 31i64, // Alice's birthday
})
})?;
```
All operations inside `db.write(|tx| { ... })` are atomic — they either all
succeed or all roll back.
---
## 6. Multi-Operation Transactions
For operations that must succeed together:
```rust
let dave = tx.create_node("Person", properties! { "name" => "Dave" })?;
tx.create_edge(carol, dave, "WORKS_WITH", properties! {})?;
Ok((carol, dave))
})?;
```
---
## 7. Time-Travel Queries
This is where AletheiaDB goes beyond ordinary graph databases. Every write is
recorded with two timestamps: **valid time** (when the fact was true in the real
world) and **transaction time** (when it was recorded in the database). You can
query at any point in either dimension.
```rust
use aletheiadb::time;
// Record the time before we make a change
let before_update = time::now();
// Update Alice's role
})?;
// Query what Alice looked like *before* the update
let historical_alice = db.get_node_at_time(
alice_id,
before_update, // valid time: what was true at this moment
before_update, // transaction time: what the DB knew at this moment
)?;
// historical_alice.properties does not have "role" — the update hadn't happened yet
println!("{:?}", historical_alice.properties.get("role")); // None
```
See [Core Concepts](core-concepts.md) for a deeper explanation of valid time vs
transaction time.
---
## 8. Vector Search (Optional)
AletheiaDB stores dense vector embeddings as node properties and indexes them
with HNSW for fast k-NN search. Enable the index before inserting nodes.
```rust
use aletheiadb::{AletheiaDB, HnswConfig, DistanceMetric};
let db = AletheiaDB::new()?;
// Enable HNSW indexing on the "embedding" property
db.vector_index("embedding")
.hnsw(HnswConfig::new(384, DistanceMetric::Cosine))
.enable()?;
let v1 = vec![0.1f32; 384];
let v2 = vec![0.9f32; 384]; // very different from v1
let doc1 = db.create_node("Document", properties! {
"title" => "Intro to Rust",
"embedding" => &v1[..],
})?;
let _doc2 = db.create_node("Document", properties! {
"title" => "Advanced Rust",
"embedding" => &v2[..],
})?;
// Find the 10 nodes most similar to doc1
// (doc1 itself is excluded from results)
let similar = db.find_similar(doc1, 10)?;
for (node_id, score) in similar {
println!("Node {:?} similarity: {:.3}", node_id, score);
}
```
---
## 9. Hybrid Queries (Graph + Vector + Temporal)
All three dimensions can be combined in a single query:
```rust
use aletheiadb::time;
let query_embedding = vec![0.1f32; 384];
let t = time::now();
// "Who does Alice know (graph), ranked by semantic similarity to my embedding
// (vector), as of a specific point in time (temporal)?"
let results = db.query()
.as_of(t, t) // temporal
.start(alice_id) // graph: start node
.traverse("KNOWS") // graph: hop
.rank_by_similarity(&query_embedding, 10) // vector: re-rank
.execute(&db)?;
for row in results {
let row = row?;
println!("Found {:?} with score {:?}", row.entity, row.score);
}
```
See [Hybrid Query Guide](hybrid-query-guide.md) for the full API.
---
## 10. Delete
```rust
// Delete a specific edge
// Delete a node AND all its connected edges (recommended)
db.write(|tx| tx.delete_node_cascade(alice_id))?;
// Delete node only (leaves orphaned edges — use carefully)
Prefer `delete_node_cascade` to avoid orphaned edges. See [Known Limitations](../../README.md#known-limitations).
---
## What's Next
You now know the core loop: create nodes and edges, query and traverse, update
with transactions, look back in time. From here:
- **Understand the model** → [Core Concepts](core-concepts.md)
- **Persist data to disk** → [Persistence Guide](PERSISTENCE.md)
- **Deep vector search** → [Vector Search Integration](vector-search-integration.md)
- **Complex hybrid queries** → [Hybrid Query Guide](hybrid-query-guide.md)
- **Production observability** → [docs/OBSERVABILITY.md](../OBSERVABILITY.md)
- **Scale horizontally** → [Sharding Guide](sharding-guide.md)
- **Connect to Claude / LLMs** → Run `cargo run --bin aletheia-mcp --features mcp-server`