DEV Community

Cover image for How I Explored Neo4j, Cypher & Graph Modeling – A Hands-On Journey

How I Explored Neo4j, Cypher & Graph Modeling – A Hands-On Journey

I recently completed the Neo4j Certified Professional exam — but for me, it wasn’t just about grabbing a badge. I genuinely wanted to learn how graph databases like Neo4j help in solving real-world problems — especially ones that involve complex relationships.

In this post, I’ll share how I learned and practiced Cypher, how I modeled data using Nodes, Relationships, Labels, and Properties, and how I’m already seeing ways to use Neo4j in my daily cloud and DevOps work.


👋 Why Neo4j? Why Graphs?

In DevOps and cloud infrastructure, most things are deeply connected:

  • IAM roles link to EC2s
  • EC2s belong to subnets, which are inside VPCs
  • Security groups touch multiple instances

Trying to answer "what connects to what" in a relational database is a headache. With Neo4j, this kind of relationship-heavy data feels natural.

Graphs let you:

  • Visualize your architecture
  • Ask intuitive questions
  • Identify risks, bottlenecks, or misconfigurations

🧱 The Basics – Nodes, Relationships, Labels, Properties

Before I show Cypher examples, here’s a quick refresher:

Concept Meaning
Node An entity like User, Server, Role
Relationship A connection like DEPLOYS_TO, USES, or PART_OF
Label A tag/category for nodes (like :Instance, :VPC)
Property A key-value pair stored on nodes

⚙️ Cypher in Action – What I Actually Used

🛠️ CREATE – Basic Graph Setup

CREATE (u:User {name: "Vishnu", role: "DevOps"})
CREATE (s:Server {name: "WebServer", type: "EC2"})
CREATE (u)-[:DEPLOYS_TO]->(s)
Enter fullscreen mode Exit fullscreen mode

Creates a user and a server node, and connects them with a DEPLOYS_TO relationship. Simple and clean.

🔁 MERGE – Safe Create

MERGE (db:Server {name: "DBServer"})
MERGE (u:User {name: "Vishnu"})
MERGE (u)-[:MONITORS]->(db)
Enter fullscreen mode Exit fullscreen mode

Prevents duplication. If the node exists, it reuses it. Otherwise, it creates it. Great for idempotent scripts.

🔍 MATCH – Query the Graph

MATCH (u:User)-[:DEPLOYS_TO]->(s:Server)
RETURN u.name, s.name
Enter fullscreen mode Exit fullscreen mode

This helped me quickly answer: Which user deploys to which server?

🌀 UNWIND – Batch Insert from a List

UNWIND ["App1", "App2", "App3"] AS app
CREATE (:Application {name: app})
Enter fullscreen mode Exit fullscreen mode

Perfect for looping over lists and creating multiple nodes. I used this when importing basic sample data.

🧹 DELETE / DETACH DELETE / REMOVE

// Delete just the relationship
MATCH (a)-[r:DEPLOYS_TO]->(b) DELETE r

// Detach and delete a node (with its relationships)
MATCH (u:User {name: "Vishnu"}) DETACH DELETE u

// Remove a property
MATCH (u:User {name: "Vishnu"}) REMOVE u.role
Enter fullscreen mode Exit fullscreen mode

These are helpful for cleaning your graph as you iterate and refactor.

📊 PROFILE – Query Optimization

PROFILE MATCH (u:User)-[:DEPLOYS_TO]->(s:Server)
RETURN u, s
Enter fullscreen mode Exit fullscreen mode

This shows execution plans — helpful if you're building large datasets and want to understand performance bottlenecks.

💡 My Use Case – Mapping Cloud Resources

Here’s how I modeled a sample AWS environment in Neo4j:

CREATE (ec2:Instance {id: "i-001", type: "t3.medium"})
CREATE (sg:SecurityGroup {name: "app-sg"})
CREATE (vpc:VPC {id: "vpc-123"})

CREATE (ec2)-[:USES]->(sg)
CREATE (ec2)-[:PART_OF]->(vpc)
Enter fullscreen mode Exit fullscreen mode
  • This setup allowed me to visualize questions like:
  • Which EC2 instance uses which security group?
  • What VPC does an instance belong to?
  • Which resources are potentially exposed?

🔍 Filtering and Refining with WHERE

MATCH (s:Server)
WHERE s.type = "EC2"
RETURN s.name, s.type
Enter fullscreen mode Exit fullscreen mode
MATCH (u:User)-[:DEPLOYS_TO]->(s:Server)
WHERE u.role = "DevOps" AND s.type = "EC2"
RETURN u.name, s.name
Enter fullscreen mode Exit fullscreen mode

This was super helpful when querying only the relevant part of the graph.

🔄 Subqueries in Cypher

Subqueries are a bit more advanced but really useful for aggregations and filtering within scope.

MATCH (u:User)
CALL {
  WITH u
  MATCH (u)-[:DEPLOYS_TO]->(s:Server)
  RETURN count(s) AS serverCount
}
RETURN u.name, serverCount
Enter fullscreen mode Exit fullscreen mode

Here, for each user, we’re counting how many servers they deploy to. This avoids unwanted cross-joins.

🔁 Why I Loved Learning This

  • Cypher feels very natural — almost like English
  • Neo4j Desktop makes it easy to visualize everything
  • Graph modeling just makes more sense for infra and security-related data

🧠 Final Thoughts

If you're working in cloud, security, or DevOps, and haven't explored graph databases yet — start now. Even a few days with Neo4j will change how you think about relationships and architecture.

Let me know how you’re using Neo4j in your stack.

Top comments (0)