Neo4j handbook for Nodejs and Python
Published on 06/05/2025
5 min read
In category
technical
A lightning‑fast handbook of the only commands you need to stand up, populate, and query a Neo4j graph from JavaScript (Node.js) or Python. Copy, paste, ship.
Basic Concepts
- Node – an entity/record; can hold multiple labels (e.g.,
:Person
,:Customer
). - Relationship – a directed, typed edge between two nodes (e.g.,
[:KNOWS]
); stores its own properties. - Property – key–value data on nodes or relationships (
name
,age
,since
). - Path – an ordered chain of nodes & relationships; assign it with
p = (a)-[:REL]->(b)
. - Cypher – the query language; core verbs:
MATCH
,CREATE
,MERGE
,SET/REMOVE
,DELETE
,RETURN/WITH
,WHERE
. - Indexes – speed up look‑ups on frequently filtered properties (
CREATE INDEX ...
). - Constraints – enforce integrity (e.g., uniqueness:
... REQUIRE email IS UNIQUE
). - Transaction – ACID wrapper around one or more operations (
session.write_transaction(...)
). - APOC / GDS – plugin libraries providing utilities (APOC) and graph algorithms (GDS) for power users.
1 Setup & Connection Setup & Connection
Install Drivers
- Node.js
npm i neo4j-driver
- Python
pip install neo4j
Connect (Bolt URI)
// Node.js
const neo4j = require('neo4j-driver');
const driver = neo4j.driver('neo4j://localhost:7687',
neo4j.auth.basic('neo4j', 'password'));
const session = driver.session({ database: 'neo4j' });
# Python
from neo4j import GraphDatabase
driver = GraphDatabase.driver('neo4j://localhost:7687',
auth=("neo4j", "password"))
with driver.session() as session:
...
Tip Use
neo4j+s://
for AuraDB or any TLS‑encrypted endpoint.
Close when done:
await session.close();
await driver.close();
session.close()
driver.close()
2 Create Nodes (Labels ≈ Tables)
await session.run(
'CREATE (p:Person {name:$name, age:$age})',
{ name: 'Alice', age: 30 }
);
session.run(
"CREATE (p:Person {name:$name, age:$age})",
{"name": "Alice", "age": 30}
)
Use parameters ($name
)—never string‑concatenate user input.
3 Create Relationships
await session.run(
'MATCH (a:Person {name:$from}), (b:Person {name:$to})\n'
+ 'CREATE (a)-[:KNOWS {since:$y}]->(b)',
{ from: 'Alice', to: 'Bob', y: 2020 }
);
session.run(
"MATCH (a:Person {name:$from}), (b:Person {name:$to}) "
"CREATE (a)-[:KNOWS {since:$y}]->(b)",
{"from": "Alice", "to": "Bob", "y": 2020}
)
4 Read / Match Patterns
Basic lookup
MATCH (p:Person {name:$name}) RETURN p;
Traversal (friends of friends)
MATCH (p:Person {name:$name})-[:KNOWS]->()-[:KNOWS]->(fof)
RETURN DISTINCT fof.name;
Retrieve in code:
const res = await session.run(query,{name:'Alice'});
res.records.forEach(r=>console.log(r.get(0)));
for record in session.run(query, name="Alice"):
print(record[0])
5 Filtering, Ordering, Pagination
MATCH (p:Person)
WHERE p.age > $minAge
RETURN p.name, p.age
ORDER BY p.name
SKIP $skip LIMIT $limit;
Params {minAge:30, skip:10, limit:5}
6 Aggregations
MATCH (p:Person)-[:KNOWS]->(f:Person)
RETURN p.name, count(f) AS friends
ORDER BY friends DESC;
Collect list:
MATCH (p)-[:KNOWS]->(f)
RETURN p.name, collect(f.name) AS friendList;
7 Shortest Path
MATCH p = shortestPath((a:Person {name:$a})-[:KNOWS*..5]-(b:Person {name:$b}))
RETURN nodes(p) AS hops;
8 Schema: Indexes & Constraints
// Uniqueness
CREATE CONSTRAINT unique_email IF NOT EXISTS
FOR (u:User) REQUIRE u.email IS UNIQUE;
// Simple index
CREATE INDEX person_name IF NOT EXISTS FOR (p:Person) ON (p.name);
List:
SHOW CONSTRAINTS; SHOW INDEXES;
9 Batch Inserts with UNWIND
const people=[{name:'Dan',age:33},{name:'Eve',age:28}];
await session.run(
'UNWIND $rows AS row CREATE (p:Person) SET p = row',
{rows: people}
);
people=[{"name":"Dan","age":33},{"name":"Eve","age":28}]
session.run(
"UNWIND $rows AS row CREATE (p:Person) SET p = row",
{"rows": people}
)
10 Transactions (Python shown)
def add_friend(tx, a, b):
tx.run("MATCH (x:Person {name:$a}), (y:Person {name:$b}) "
"MERGE (x)-[:KNOWS]->(y)", a=a, b=b)
with driver.session() as s:
s.write_transaction(add_friend, "Alice", "Carol")
Node.js equivalent: await session.executeWrite(tx=>tx.run(...))
11 Profile & Tune
EXPLAIN <query>
→ show plan without running.PROFILE <query>
→ run & return db‑hits, rows, time.- Look for NodeByLabelScan (slow). Add indexes until you see NodeIndexSeek / NodeIndexScan.
12 Close & Cleanup
Always:
await session.close();
await driver.close();
session.close()
driver.close()
Mini‑Glossary
Term | Meaning |
---|---|
Node | Entity / record (row) |
Label | Node tag (table name) |
Relationship | Typed, directed edge |
Property | Key–value on node/rel |
Path | Ordered chain of nodes & relationships |
Cypher | Query language |
One‑Minute Warm‑up Script (Node.js)
import neo4j from 'neo4j-driver';
const d = neo4j.driver('neo4j://localhost', neo4j.auth.basic('neo4j','pass'));
const s = d.session();
await s.run("CREATE (:Person {name:'Neo'})");
const res = await s.run("MATCH (n:Person) RETURN n.name AS name");
console.log(res.records[0].get('name')); // -> Neo
await s.close();
await d.close();
Print this page, stick it on your monitor, and graph fearlessly. 🚀
comment