Built for knowledge

Every component of InferaGraph is designed to make working with knowledge graphs intuitive, fast, and intelligent.

Graph Engine

Structured data,
blazing traversal

At the core of InferaGraph is a high-performance, in-memory graph store with copy-on-write semantics and multi-index lookups.

Typed Nodes and Edges

People, places, events, groups—with gender, era, tags, and custom attributes.

Multi-Index Lookups

Instant retrieval by type, tag, or case-insensitive name search.

BFS Traversal

Neighborhood queries with configurable depth and bidirectional edge walking.

Pathfinding

Breadth-first shortest path between any two nodes in the graph.

Subgraph Extraction

Pull out connected subsets for focused analysis or visualization.

// Full-text search with relevance scoring
const results = search.search('important');
// → [{ nodeId: 'node-1', score: 10 }, ...]

// Find shortest path
const path = query.findPath('node-1', 'node-5');
// → ['node-1', 'node-3', 'node-5']

// Get neighborhood (depth=2)
const nearby = query.getNeighbors('node-1', 2);

// Filter by any attribute
const active = filter.filterByAttribute('status', 'active');

// Custom predicates
const tagged = filter.filter(
  (attrs) => attrs.tags?.includes('important')
);
User Query

"What is the lineage from Abraham to King David?"

Tool Dispatch

apply_filter({ predicate })
highlight([abraham ... david])
focus(abraham)
annotate(david, "King of Israel")

AI Response

The lineage from Abraham to King David spans 14 generations through the tribe of Judah...

abraham isaac jacob david +10 highlighted
AI-First Reasoning

Natural language meets
structured knowledge

Pass in an LLM provider and InferaGraph handles the rest. User queries chain with developer-set scope, the model emits typed tool calls (apply_filter, highlight, focus, annotate), and the library applies them to the graph visually—your code never has to.

Provider Injection

The host imports a provider package and passes it in. InferaGraph never invokes the LLM directly—your keys, your terms, your rate limits.

Predicate + NLQ Chain

Developer sets the scope (predicate); the user drives natural-language queries. Both compose as a single reasoning chain.

Tool-Call Dispatch

The LLM emits apply_filter, highlight, focus, annotate. The library applies them visually—nothing leaks into your UI code.

Visualization

See the connections
in three dimensions

WebGL-powered 3D rendering with real physics simulation. Toggle between animated force-directed graphs and static card-style hierarchies — org charts, supply chains, taxonomies, family trees, anything with a parent → child shape.

Force-Directed 3D

Barnes-Hut N-body with O(n log n) performance

Tree Layout

Card-style hierarchy with static nodes and orthogonal connectors — org charts, supply chains, taxonomies, family trees

CSS Themeable

Custom properties for colors, fonts, sizing

Interactive

Aggregated edge descriptions on hover with smart tooltips

// Floating graph view with animated physics
<GraphProvider layout="graph" layoutOptions={{ animated: true }}>
  <InferaGraph />
</GraphProvider>

// Static hierarchy (org chart, taxonomy, family tree, …) with card-style nodes
<GraphProvider layout="tree" layoutOptions={{ animated: false }}
  nodeRender={{ style: 'card' }}>
  <InferaGraph />
</GraphProvider>

Persistent Layout State — 0.14.6

Node positions and camera state are cached per layout mode. Toggling Graph ↔ Tree restores the same viewport instead of reseeding the force simulation, so users keep their mental map across mode switches. Automatic — no host wiring.

Streaming Chat

One hook,
a conversation with the graph

useInferaGraphChat() returns a chat() function whose AsyncIterable yields text deltas to your UI and dispatches tool calls into the graph. You bring the input box; the library handles everything between the keystroke and the visual answer.

useInferaGraphChat

React hook returning an async chat() — host owns the input field, library owns the graph response.

Streaming Events

AsyncIterable<ChatEvent> yields text deltas to the UI; tool calls are handled internally and update the graph.

Pluggable Transport

inProcessTransport for browser-safe providers, httpTransport({ url }) for Next.js-style server-side AIEngine over SSE.

AbortSignal Support

Cancel in-flight chat turns cleanly from React effects or user interactions.

import { useInferaGraphChat } from '@inferagraph/core/react';

function Ask() {
  const { chat } = useInferaGraphChat();
  const [text, setText] = useState('');

  async function onSubmit(message) {
    // Tool calls (filter / highlight / focus / annotate)
    // are applied to the graph automatically.
    for await (const event of chat(message)) {
      if (event.type === 'text') {
        setText(prev => prev + event.delta);
      }
    }
  }
}
// Stream AI responses in real-time
for await (const chunk of ai.queryStream('Who are the 12 tribes?')) {
  if (chunk.type === 'text') {
    process.stdout.write(chunk.content);
  }
}

// Provider-level streaming
for await (const chunk of provider.stream(request)) {
  // { type: 'text'|'done'|'error', content: string }
}
Low-level streaming

Drop down to the provider
when you need to

Need raw token streaming without the chat tool layer? Every provider exposes a native stream() AsyncIterable for direct use.

AsyncIterable API

for-await-of streaming with LLMStreamChunk type (text/done/error).

Provider Native

Each provider implements native streaming—Anthropic events, OpenAI deltas, Azure chunks.

Backward Compatible

Default stream() falls back to complete() for providers that don't override.

import { useInferaGraphSearch } from '@inferagraph/core/react';

const { search } = useInferaGraphSearch();

// Short tokens → keyword search
const a = await search('abraham');

// Full sentences → semantic search via embeddings
const b = await search(
  'patriarchs who left their homeland in faith'
);
// → ranked by semantic similarity
Semantic Search

Search by meaning,
not just by name

useInferaGraphSearch() auto-detects intent: short tokens hit the keyword index; sentence-length queries run vector search via embeddings. Same API, the right answer either way.

Auto-Detect Mode

Short tokens run keyword search; sentence-length inputs run semantic search via embeddings. One API, both behaviors.

Three-Tier Storage

Omit for keyword-only, pass cache for cache-as-store, or pass a dedicated EmbeddingStore for vector-native backends.

Provenance Metadata

Every embedding is stamped with model, version, and content hash. Unchanged content is never re-embedded.

Inferred Relationships

Connections the schema
didn't make explicit

AI-discovered links between nodes the authored graph never wired up directly, rendered as dashed edges that track positions live through the force simulation. The library handles fetch, render, and per-tick updates — the host just toggles showInferredEdges.

RemoteInferredEdgeStore

Browser-side InferredEdgeStore impl that fetches edges from a URL with in-memory caching — drop into <InferaGraph> and the library handles fetch + render.

createInferredEdgeRouteHandler

Next.js / Express helper that serves computed edges from the configured store. lazyCompute: true lets the first uncached request trigger the LLM-driven inference path on demand.

InferredEdgeMesh.updatePositions

Per-tick BufferAttribute mutation keeps dashed edges visually locked to moving nodes during the force simulation — no re-allocation, no flicker.

onInferredEdgesLoadingChange

Callback prop on <InferaGraph> drives a host-side spinner / busy-state. Pair with showInferredEdges to wire a checkbox in one line.

Full pipeline — architecture, server setup, persistence options, compute triggers, and the 0.15.0 breaking-change note — lives in Docs → Inferred Edges.

// Server (Next.js App Router) — serve computed edges from any InferredEdgeStore.
import { createInferredEdgeRouteHandler } from '@inferagraph/core';
import { engine } from '@/lib/inferagraph';

export const GET = createInferredEdgeRouteHandler(engine, {
  lazyCompute: true,   // first uncached request triggers the LLM inference path
});

// Browser — point the library at the route; the rest is automatic.
import { InferaGraph, RemoteInferredEdgeStore } from '@inferagraph/core/react';

<InferaGraph
  data={data}
  inferredEdgeStore={new RemoteInferredEdgeStore('/api/inferred-edges')}
  showInferredEdges={showInferred}
  onInferredEdgesLoadingChange={setLoading}
/>
Caching & Persistence

Don't pay twice
for the same answer

A pluggable CacheProvider sits between InferaGraph and the LLM. Use the in-memory default for development, switch to Redis for production deploys. The cache is bound to the provider instance, so swapping models never serves stale completions.

Pluggable CacheProvider

In-memory lruCache by default; swap in @inferagraph/redis, cosmosCacheProvider from @inferagraph/cosmosdb, or sqlCacheProvider from @inferagraph/sql for production.

Provider-Bound Invalidation

Cache is keyed to the LLM provider instance. Switching providers flushes stale completions automatically.

Embedding Reuse

Pair the cache with auto-detect search to reuse embeddings across sessions without re-billing the model.

import { lruCache } from '@inferagraph/core/data';
import { redisCacheProvider } from '@inferagraph/redis';

// Dev: in-memory
<InferaGraph data={data} llm={provider}
  cache={lruCache()} />

// Production: Redis
<InferaGraph data={data} llm={provider}
  cache={redisCacheProvider({
    url: process.env.REDIS_URL,
    prefix: 'inferagraph:',
  })} />
Data Features

Manage your graph
with precision

Serialization, temporal navigation, and semantic clustering for advanced graph management.

Serialization

Versioned Schema

Version-stamped JSON with nodes, edges, and metadata for forward compatibility.

Round-Trip Safe

toJSON() and fromJSON() preserve all data, including custom attributes.

Helpers

exportGraph() and importGraph() for string-based serialization.

// Serialize to versioned JSON
const data = store.toJSON();
// { version: 1, nodes: [...], edges: [...], metadata: {...} }

// Restore from JSON
store.fromJSON(data);

// String helpers
const json = exportGraph(store);
importGraph(store, json);

Temporal Navigation

Configurable Eras

Define your own eras with custom date ranges, names, and descriptions.

Time Range Queries

Filter nodes by arbitrary year range, overlapping eras, or specific year.

Era Transitions

Compute appearing, disappearing, and persisting nodes between eras.

const timeline = new TimelineEngine(store, {
  eras: [
    { name: 'Ancient', startYear: -3000, endYear: -500 },
    { name: 'Classical', startYear: -500, endYear: 500 },
  ],
  eraKey: 'era',
});

// Filter by era
const ancient = timeline.getNodesByEra('Ancient');

// Filter by year range
const nodes = timeline.getNodesByTimeRange({
  start: -500, end: 500
});

// Compute transitions
const t = timeline.getTransition('Ancient', 'Classical');
// { appearing: [...], disappearing: [...], persisting: [...] }

Semantic Clustering

Community Detection

Louvain-inspired modularity optimization groups densely-connected nodes.

Expand/Collapse

Collapse clusters to a single representative node; expand to reveal contents.

Convex Hull

Graham scan computes visual cluster boundaries from node positions.

const clusters = new ClusterEngine(store);

// Detect communities
const detected = clusters.detectCommunities();

// Collapse/expand
clusters.collapse(detected[0].id);
const visible = clusters.getVisibleNodes();

// Cluster boundary (convex hull)
const hull = clusters.getClusterBoundary(
  detected[0].id, positions
);
Interaction

Full control over
every interaction

Multi-Select

Selection Modes

Replace (click), Add (Shift+click), Toggle (Ctrl/Cmd+click).

Drag-Box Select

Marquee selection by screen rectangle with configurable mode.

Batch Operations

Delete, move, group, and extract subgraph from selected nodes.

Minimap

Canvas Overlay

Lightweight canvas rendering of all node positions at minimap scale.

Viewport Sync

Viewport rectangle updates in real-time as the main camera moves.

Click-to-Navigate

Click anywhere on the minimap to center the main view on that position.

Keyboard Navigation

Focus Navigation

Tab/Shift+Tab cycles through nodes; Arrow keys traverse graph edges.

Selection Keys

Enter/Space to select focused node; Escape to deselect all.

Custom Shortcuts

Register custom key bindings with modifier support (Ctrl, Shift, Alt, Meta).

ARIA Accessible

Sets tabindex, role, and aria-label on the container for screen readers.

Export

PNG Export

Canvas toDataURL/toBlob with configurable resolution scale.

SVG Export

Generate clean SVG from node/edge positions—no Three.js dependency.

JSON Export

Leverages graph serialization with optional metadata and selection filtering.

const exporter = new ExportEngine(store);

// Export as JSON (uses serialization)
const json = exporter.exportJSON();

// Export as SVG
const svg = exporter.exportSVG(nodes, edges, {
  width: 1024, height: 768
});

// Export as PNG from canvas
const dataUrl = exporter.exportPNG(canvas, {
  scale: 2
});

// Export selected only
const partial = exporter.exportJSON({
  selectedOnly: true,
  selectedNodeIds: selection.getSelected()
});
Data Layer

Any data source,
any backend

The DataAdapter interface decouples InferaGraph from your data layer. Load from static files, REST APIs, or connect directly to databases with pre-built datasource packages. The accumulating cache ensures data is fetched incrementally and never re-requested.

Framework-Agnostic

DataAdapter interface works with any backend—REST, GraphQL, WebSocket, or direct DB.

Incremental Loading

On-demand fetching with expandNode, findPath, search, and getContent.

Accumulating Cache

DataManager merges fetched data into the local GraphStore—no duplicate requests.

Static Adapter

Built-in StaticDataAdapter wraps in-memory data for simple use cases.

Server Datasources

Pre-built packages for Gremlin, Cosmos DB, SQL (PostgreSQL, MySQL, SQLite, MSSQL), local files, and Azure Log Analytics.

Any Backend

Extend the DataSource base class to connect to any data source with managed lifecycle.

// Static data (simple)
<GraphProvider data={myGraphData}>
  <InferaGraph />
</GraphProvider>

// Dynamic adapter (any backend)
<GraphProvider adapter={apiAdapter}>
  <InferaGraph />
</GraphProvider>

// Server-side datasource (factory)
const ds = sqlDataSource({
  dialect: 'postgres',
  connection: process.env.DATABASE_URL,
});
await ds.connect();
<GraphProvider adapter={ds}>
  <InferaGraph />
</GraphProvider>
Developer Experience

Built for developers

TypeScript-first, tree-shakeable, and designed to integrate seamlessly with your stack.

T

TypeScript Strict

Full type inference, strict mode, and generated .d.ts declarations.

R

React Integration

Context provider, useInferaGraph hook, and a drop-in InferaGraph component.

E

ESM + CJS

Dual-format builds via tsup. Works everywhere—bundlers, Node, and Deno.

P

Plugin API

Register custom layouts, providers, and renderers with type-safe plugin context.

S

Themeable

CSS custom properties for every visual element. Ship light, dark, or custom themes.

V

Tested

Test-driven discipline with 80%+ coverage enforced. Comprehensive suites cover every feature.

D

Runtime Debugging — IG_DEBUG (0.14.6)

Flip on diagnostic logs at runtime — no rebuild, no source edits. Trace layout positions, camera state, embedding fetches, inferred-edge dispatch, and tool-call outcomes from DevTools while reproducing an issue.

// In DevTools console — takes effect on the next library log.
globalThis.IG_DEBUG = true;

// Turn it back off the same way.
globalThis.IG_DEBUG = false;

Ready to build?

Get started with InferaGraph in under a minute.

Read the Documentation