Amazon Neptune

Amazon Neptune is AWS’s fully managed graph database service, supporting both property-graph (Apache TinkerPop / Gremlin and openCypher) and RDF / SPARQL models. Neptune handles provisioning, patching, replication, and backup; users get a graph endpoint, AWS-native IAM authentication, and integration with the rest of the AWS data stack.

The sections below cover Neptune's cluster architecture, its two data models, bulk loading from S3, Gremlin and openCypher examples, and the operational trade-offs to plan for.

1. Key Features

2. Neptune vs. Neo4j

3. Use Cases

4. Architecture

Neptune Cluster Architecture Application Gremlin / openCypher Cluster endpoint Reader endpoint Writer instance Read replica Read replica Shared cluster volume 6 copies across 3 AZs, grows automatically Compute and storage are separate: replicas read the same volume, so they add no storage copies.

A Neptune cluster has one writer instance and optional read replicas, all attached to a single distributed storage volume that AWS replicates six ways across three Availability Zones. Because replicas read the same volume, they do not copy data from the writer, and replica lag is typically short. Applications connect through the cluster endpoint for writes and the reader endpoint, which load-balances across replicas, for read-only queries. If the writer fails, a replica is promoted. Neptune runs inside a VPC only; there is no public endpoint, so clients must be in the VPC, a peered network or behind a proxy. IAM database authentication can be enabled so requests are signed with AWS credentials instead of relying solely on network controls.

5. Data model

Neptune stores either a property graph or RDF. For property graphs, vertices and edges have labels and properties and are queried with Gremlin or openCypher; both languages can read the same property-graph data. For RDF, data is a set of subject–predicate–object triples (quads, with a named graph) queried with SPARQL. Property-graph and RDF data are separate models and are not queried interchangeably, so the choice should follow the problem: property graphs for application data such as accounts and devices, RDF when you need standard ontologies, linked data or inferencing vocabularies.

6. Loading data

Bulk Load Data Flow Source systems RDBMS, logs Export to CSV nodes + edges files Amazon S3 bucket in same region Loader API POST /loader Neptune graph ready The cluster needs an IAM role with S3 read access and a VPC endpoint for S3. Vertex files carry ~id and ~label columns; edge files add ~from and ~to.

Row-by-row inserts are fine for application writes but slow for an initial load. The bulk loader reads CSV (property graph) or RDF serialisations such as N-Triples and Turtle directly from S3 in parallel. You start a job with an HTTP request to the loader endpoint and poll its status by job ID.

curl -X POST https://my-cluster.cluster-xxxx.us-east-1.neptune.amazonaws.com:8182/loader \
  -H 'Content-Type: application/json' -d '{
    "source": "s3://my-bucket/graph/",
    "format": "csv",
    "iamRoleArn": "arn:aws:iam::123456789012:role/NeptuneLoadFromS3",
    "region": "us-east-1",
    "failOnError": "FALSE"
  }'

7. Example queries

from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
from gremlin_python.process.anonymous_traversal import traversal
from gremlin_python.process.traversal import P

g = traversal().withRemote(DriverRemoteConnection(
    "wss://my-cluster.cluster-xxxx.us-east-1.neptune.amazonaws.com:8182/gremlin", "g"))

# accounts that share a device with account A123 (a common fraud signal)
others = (g.V().has("account", "id", "A123").as_("a")
           .out("used").in_("used")
           .where(P.neq("a"))
           .dedup().values("id").toList())
print(others)
// openCypher over HTTPS (/openCypher endpoint), same data
MATCH (a:account {id: 'A123'})-[:used]->(d:device)<-[:used]-(other:account)
WHERE other <> a
RETURN DISTINCT other.id;

The traversal walks from an account to the devices it used and back to every account that used those devices. In fraud detection this two-hop pattern surfaces account rings that share hardware. The as_("a") step labels the starting vertex so the where filter can exclude it from the results, which is the Gremlin equivalent of the other <> a clause in the Cypher version.

8. Pitfalls and trade-offs

See Neo4j and graph modelling, JanusGraph for another Gremlin-compatible engine, and AWS Databases for other managed AWS stores.