Every component of InferaGraph is designed to make working with knowledge graphs intuitive, fast, and intelligent.
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')
);"What is the lineage from Abraham to King David?"
apply_filter({ predicate })
highlight([abraham ... david])
focus(abraham)
annotate(david, "King of Israel")
The lineage from Abraham to King David spans 14 generations through the tribe of Judah...
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.
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.
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 }
}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 similarityuseInferaGraphSearch() 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.
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}
/>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:',
})} />Provider Ecosystem
@inferagraph/openai-provider
Chat and embeddings via OpenAI.
@inferagraph/anthropic-provider
Claude chat; optional embeddings via Voyage AI.
@inferagraph/azure-foundry-provider
Chat via Azure AI Foundry deployments.
@inferagraph/redis
NewProduction-ready Redis-backed cache.
@inferagraph/cosmosdb
Azure Cosmos DB document graph adapter.
@inferagraph/gremlin
Apache TinkerPop / Cosmos Gremlin / Neptune.
Serialization, temporal navigation, and semantic clustering for advanced graph management.
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);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: [...] }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
);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.
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.
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.
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()
});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>Gremlin
Apache TinkerPop graphs—Cosmos DB Gremlin API, Neptune, JanusGraph.
Cosmos DB
Azure Cosmos DB NoSQL API—nodes and edges as JSON documents.
SQL
PostgreSQL, MySQL, SQLite, or MSSQL via Knex with auto-migration.
File
NewCSV, TSV, or a folder of Markdown files with strict frontmatter validation.
Log Analytics
NewAzure Log Analytics via KQL—app registration, managed identity, or behind APIM.
TypeScript-first, tree-shakeable, and designed to integrate seamlessly with your stack.
Full type inference, strict mode, and generated .d.ts declarations.
Context provider, useInferaGraph hook, and a drop-in InferaGraph component.
Dual-format builds via tsup. Works everywhere—bundlers, Node, and Deno.
Register custom layouts, providers, and renderers with type-safe plugin context.
CSS custom properties for every visual element. Ship light, dark, or custom themes.
Test-driven discipline with 80%+ coverage enforced. Comprehensive suites cover every feature.
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;