Neo4j Virtual Graph: Querying Federated Data Sources as a Single Knowledge Graph
Teaser: Neo4j Virtual Graph lets you query PostgreSQL, MongoDB, BigQuery, Snowflake, and REST APIs through Cypher as if they were part of your knowledge graph — no ETL, no data movement, no duplication. This article explores the architecture (query compiler, connector agent, schema mapper), three practical query patterns (pure federated, hybrid physical/virtual, incremental materialisation), and production performance benchmarks.
Introduction
In July 2026, Neo4j announced the public preview of Neo4j Virtual Graph — a capability that lets you query external data sources through the Cypher query language as if they were part of your Neo4j graph database. No data movement, no ETL pipelines, no duplication.
Virtual Graph extends the concept of graph federation — the ability to project a graph-shaped query interface over non-graph data stores. It connects to PostgreSQL, MySQL, MongoDB, Google BigQuery, Snowflake, and REST APIs, mapping their schemas to virtual node labels and relationship types that Cypher queries can traverse.
For teams managing enterprise knowledge graphs, this addresses a recurring friction point: the data that belongs in your graph already lives in operational databases, data warehouses, and SaaS APIs. Virtual Graph lets you query it in place, then materialise only what earns its place in the persistent graph.
What Is a Virtual Knowledge Graph?
A virtual knowledge graph presents a graph-shaped view of non-graph data without physically transforming or copying it. The concept builds on decades of research in ontology-based data access (OBDA) and virtual graph databases, but Neo4j's implementation is distinctive in two ways:
-
Full Cypher support — Queries are not translated into a limited subset of SQL. Virtual Graph compiles Cypher into native queries against the target system, supporting
MATCH,OPTIONAL MATCH, aggregation,UNION, and subqueries. -
Bi-directional federation — Queries can join virtual nodes (from external sources) with physical nodes (stored in Neo4j) in a single Cypher statement, enabling hybrid graph traversals.
Architecture
Virtual Graph runs as a query compiler within the AuraDB Enterprise control plane, with a lightweight connector agent deployed in the customer's network:
┌───────────────────────────────────────────────────────┐
│ Cypher Query │
│ MATCH (c:Customer)-[:ORDERED]->(o:Virtual:Order) │
│ WHERE c.region = 'EMEA' │
│ RETURN c.name, o.total, o.date │
└───────────────────────┬───────────────────────────────┘
│
┌───────────────────────▼───────────────────────────────┐
│ Neo4j Virtual Graph Engine │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Schema │ │ Query │ │ Result │ │
│ │ Mapper │─▶│ Compiler │─▶│ Merger │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ ┌──────▼──────┐ ┌──────▼──────┐ │ │
│ │ Connector │ │ Optimiser │ │ │
│ │ Registry │ │ • Predicate │ │ │
│ │ │ │ pushdown │ │ │
│ │ • JDBC │ │ • Limit │ │ │
│ │ • MongoDB │ │ pushdown │ │ │
│ │ • BigQuery │ │ • Join │ │ │
│ │ • REST │ │ planning │ │ │
│ └─────────────┘ └─────────────┘ │ │
└───────────────────────────────────────────┼──────────┘
│
┌──────────────────────────────────┼──────────────────┐
│ Customer Network │ │
│ ┌───────────────────────────────▼──────────────┐ │
│ │ Virtual Graph Connector Agent │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │PostgreSQL│ │ MongoDB │ │ REST API │ ... │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
Schema Mapping
Virtual Graph requires a semantic mapping that describes how source schemas translate into graph terms. Mappings are defined in YAML and stored in the Aura Console:
name: "ecommerce-federation"
sources:
- name: postgres-orders
type: jdbc
connection: "jdbc:postgresql://host:5432/orders"
mappings:
- source: postgres-orders
table: customers
node_label: Customer
columns:
id: { property: customerId, type: string }
name: { property: name }
email: { property: email }
region: { property: region }
- source: postgres-orders
table: orders
node_label: Order
properties:
id: { property: orderId }
total: { property: total, type: float }
date: { property: orderDate, type: datetime }
- source: postgres-orders
relationship:
from: customers
to: orders
type: ORDERED
foreign_key: orders.customer_id -> customers.id
Once mapped, the virtual schema appears in Neo4j's schema introspection:
CALL db.schema.virtual()
// Returns: Node labels: [Customer, Order, Product]
// Relationship types: [ORDERED, CONTAINS]
Query Patterns
Pattern 1: Pure Federated Query
Query data entirely from external sources without involving the local graph:
MATCH (c:Customer)-[:ORDERED]->(o:Virtual:Order)
WHERE c.region = 'EMEA'
AND o.total > 1000
AND o.date >= date('2026-01-01')
RETURN c.name, count(o) AS orderCount, sum(o.total) AS totalSpend
ORDER BY totalSpend DESC
Virtual Graph compiles this into a SQL query against PostgreSQL, pushes down the predicate filters (region = 'EMEA', total > 1000, date >= '2026-01-01'), and returns only the aggregated result set.
Pattern 2: Hybrid Query (Virtual + Physical)
Join virtual nodes from an external database with physical nodes stored in Neo4j:
MATCH (c:Virtual:Customer)-[:ORDERED]->(o:Virtual:Order)
MATCH (c)-[:HAS_PROFILE]->(p:Profile)
WHERE o.total > 5000
AND p.segment IN ['enterprise', 'strategic']
RETURN c.name, p.segment, count(o) AS largeOrders
Here Customer and Order are virtual (PostgreSQL), while Profile is a physical Neo4j node. The query engine partitions the query: it pushes the Customer→Order traversal to PostgreSQL, fetches the matching customer IDs, joins them against the in-graph Profile nodes, and merges results.
sequenceDiagram
participant Client as Cypher Client
participant VGE as Virtual Graph Engine
participant PG as PostgreSQL (Virtual)
participant Neo4j as Neo4j (Physical)
Client->>VGE: MATCH (c:Virtual:Customer)-[:ORDERED]->(o:Virtual:Order)
VGE->>PG: SELECT c.id, c.name FROM customers c WHERE c.region = 'EMEA'
PG-->>VGE: {id: 101, name: "Acme"}
VGE->>Neo4j: MATCH (c:Customer {id: 101})-[:HAS_PROFILE]->(p:Profile)
Neo4j-->>VGE: {segment: "enterprise"}
VGE-->>Client: Merged result: Customer + Profile
Pattern 3: Incremental Materialisation
Virtual Graph supports CALL procedures for materialising subsets of virtual data into the physical graph:
// Identify high-value customers from the virtual layer
MATCH (c:Virtual:Customer)-[:ORDERED]->(o:Virtual:Order)
WITH c, sum(o.total) AS lifetimeValue
WHERE lifetimeValue > 100000
CALL graph.virtual.materialize(c, { label: "VIPCustomer" })
YIELD nodeId
MATCH (vip:VIPCustomer) WHERE id(vip) = nodeId
SET vip.lifetimeValue = lifetimeValue
This pattern lets teams start with a full virtual graph, then selectively materialise the most valuable subsets into Neo4j for graph-native features like GDS algorithms or vector indexes.
Performance Characteristics
Virtual Graph's query compiler applies several optimisations:
| Optimisation | Description | Impact |
|---|---|---|
| Predicate pushdown | Filters applied at source before data transfer | ~10–100× reduction in data volume |
| Limit pushdown | LIMIT clauses pushed to source query | Avoids full table scans |
| Join planning | Determines optimal join order across sources | 2–5× faster multi-source joins |
| Result streaming | Results streamed, not buffered | Supports gigabyte-scale result sets |
| Connector caching | Schema metadata cached for 5 min | Eliminates repeated DESCRIBE calls |
In benchmarks against a 10 GB PostgreSQL instance with 50 million rows, Virtual Graph's predicate-pushed queries achieved 85–95% of native PostgreSQL query latency, while cross-source joins added 10–30ms of federation overhead.
Use Cases
Data Lake Querying
Replace point-to-point ETL jobs with on-demand graph federation. Query your data lake (Snowflake, BigQuery) through Cypher without moving data into Neo4j:
MATCH (p:Virtual:Product)
WHERE p.category = 'semiconductor'
AND p.inventoryStatus = 'critical'
MATCH (s:Virtual:Supplier)-[:SUPPLIES]->(p)
RETURN s.name, p.name, p.leadTimeDays
ORDER BY p.leadTimeDays DESC
Operational Data Federation
Join real-time operational data (PostgreSQL order system) with your knowledge graph (product ontology, customer segments) without duplicating operational data:
MATCH (o:Virtual:Order)-[:CONTAINS]->(p:Virtual:Product)
MATCH (p)-[:IS_A]->(cat:Category {name: 'HighValue'})
WHERE o.status = 'pending_fulfillment'
RETURN o.orderId, p.name, o.shippingAddress
Legacy System Integration
Wrap legacy mainframe or COBOL data sources behind REST APIs, then map them as virtual graph nodes — no modifications to the legacy system required.
Limitations (Public Preview)
| Limitation | Details |
|---|---|
| Read-only | Virtual Graph supports queries only. Writes (CREATE, SET, DELETE) target physical nodes only. |
| Connector availability | JDBC (PostgreSQL, MySQL, MariaDB), MongoDB, BigQuery, Snowflake, REST. More connectors upcoming. |
| Predicate pushdown depth | Pushed down to a maximum of 3 JOINs per source; deeper joins computed in memory. |
| Transactionality | Each source participates in its own transaction scope. No distributed transactions across sources. |
| Schema changes | Source schema changes require remapping. CALL db.schema.virtual.refresh() updates cached metadata. |
Comparison: Virtual Graph vs Alternatives
| Feature | Neo4j Virtual Graph | Apache Calcite | Dremio | GraphQL Federation |
|---|---|---|---|---|
| Graph query model | ✅ Cypher (native) | ❌ SQL | ❌ SQL | ⚠️ GraphQL |
| Hybrid physical/virtual | ✅ First-class | ❌ | ❌ | ❌ |
| Predicate pushdown | ✅ Deep (3 JOINs) | ✅ Deep | ✅ Deep | ⚠️ Limited |
| Schema mapping | YAML declarative | SQL DDL | GUI | SDL |
| MCP support | ✅ (via Aura MCP) | ❌ | ❌ | ❌ |
| Deployment | AuraDB Enterprise | Self-hosted | Cloud/Self-hosted | Cloud/Self-hosted |
Getting Started
Neo4j Virtual Graph is available in public preview on AuraDB Enterprise. Enable it from the Aura Console under Database Settings → Virtual Graph.
- Deploy the Virtual Graph Connector Agent in your network (Docker image provided by Neo4r)
- Define your schema mappings in the Aura Console
- Query virtual nodes using Cypher — prefix virtual labels with
Virtual:or configure an alias - Use
CALL db.schema.virtual()to inspect available virtual entities
Documentation is live at neo4j.com/docs/aura/virtual-graph (July 2026).
Conclusion
Neo4j Virtual Graph redefines the boundary between the knowledge graph and the data sources it draws from. Instead of forcing a binary choice — ETL everything into the graph or query sources separately — Virtual Graph lets you project a graph over your existing data estate and materialise only what matters.
For organisations building enterprise knowledge graphs, this is a paradigm shift. The question is no longer "what data can I get into Neo4j?" but "what questions do I want to ask across all my data?" — and the graph model provides the answer.