Dgraph is a distributed, transactional graph database built for production workloads. It uses a native GraphQL-like query language called DQL (Dgraph Query Language), supports ACID transactions, and scales horizontally across multiple nodes. Dgraph splits responsibilities between two main components – Zero (cluster coordinator) and Alpha (data server) – giving you fine-grained control over replication, sharding, and cluster membership.
This guide walks through installing Dgraph v25.3.0 on Ubuntu 24.04 LTS, starting the cluster services, defining a schema, running mutations and queries, and setting up systemd services for production use. The same steps apply to Ubuntu 22.04 with no changes.
Prerequisites
Before starting, confirm you have the following in place:
- A server running Ubuntu 24.04 LTS with at least 4 GB RAM and 2 CPU cores
- Root or sudo access
- Ports 5080, 6080, 7080, 8080, and 9080 available (not used by other services)
- Docker installed if using the container method – see Install Docker on Ubuntu 24.04
Step 1: Install Dgraph on Ubuntu 24.04
Dgraph ships as a single binary that handles both Zero and Alpha roles. You can install it directly from the official release tarball or run it as a Docker container.
Method 1: Binary Installation
Download the latest Dgraph v25.3.0 release from GitHub and extract it to your system path.
wget https://github.com/dgraph-io/dgraph/releases/download/v25.3.0/dgraph-linux-amd64.tar.gz
sudo tar -xzf dgraph-linux-amd64.tar.gz -C /usr/local/bin
Verify the installation by checking the version:
dgraph version
The output confirms Dgraph v25.3.0 is installed and ready:
Dgraph version : v25.3.0
Dgraph codename : dgraph
Dgraph SHA-256 : [build hash]
Commit timestamp : 2026-03-06
Branch : HEAD
Go version : go1.24
Clean up the downloaded archive:
rm -f dgraph-linux-amd64.tar.gz
Method 2: Docker Installation
If you prefer containers, pull the official Dgraph image from Docker Hub.
docker pull dgraph/dgraph:v25.3.0
Confirm the image downloaded successfully:
docker images dgraph/dgraph
You should see the Dgraph image listed with the v25.3.0 tag:
REPOSITORY TAG IMAGE ID CREATED SIZE
dgraph/dgraph v25.3.0 abc123def456 2 weeks ago 150MB
For a quick standalone setup that runs both Zero and Alpha in a single container, use the standalone image:
docker run -d --name dgraph \
-p 5080:5080 -p 6080:6080 \
-p 8080:8080 -p 9080:9080 \
-v ~/dgraph:/dgraph \
dgraph/standalone:v25.3.0
The standalone image is good for development and testing. For production, run Zero and Alpha as separate processes or containers as described in the following steps.
Step 2: Start Dgraph Zero (Cluster Coordinator)
Dgraph Zero manages the cluster – it tracks Alpha nodes, assigns data shards, and handles rebalancing. Every Dgraph deployment needs at least one Zero node running before any Alpha can join.
Create data directories for Zero:
sudo mkdir -p /var/lib/dgraph/zero
sudo mkdir -p /var/log/dgraph
Start Dgraph Zero, binding it to the default ports 5080 (gRPC) and 6080 (HTTP):
dgraph zero --wal /var/lib/dgraph/zero/zw --telemetry "reports=false;" > /var/log/dgraph/zero.log 2>&1 &
Check that Zero is running and listening on its ports:
ss -tlnp | grep -E '5080|6080'
You should see both ports bound to the dgraph process:
LISTEN 0 4096 *:5080 *:* users:(("dgraph",pid=1234,fd=7))
LISTEN 0 4096 *:6080 *:* users:(("dgraph",pid=1234,fd=8))
You can also query the Zero health endpoint to confirm it is the cluster leader:
curl http://localhost:6080/state | python3 -m json.tool | head -20
Step 3: Start Dgraph Alpha (Data Server)
Dgraph Alpha handles all data storage, indexing, queries, and mutations. It connects to Zero on startup to join the cluster and receive shard assignments.
Create the Alpha data directory:
sudo mkdir -p /var/lib/dgraph/alpha
Start Dgraph Alpha, pointing it at the running Zero instance:
dgraph alpha --zero localhost:5080 \
--postings /var/lib/dgraph/alpha/p \
--wal /var/lib/dgraph/alpha/w \
--tmp /var/lib/dgraph/alpha/t \
--telemetry "reports=false;" > /var/log/dgraph/alpha.log 2>&1 &
Verify Alpha is running and listening on ports 7080 (internal gRPC), 8080 (HTTP/GraphQL), and 9080 (external gRPC):
ss -tlnp | grep -E '7080|8080|9080'
All three Alpha ports should show as listening:
LISTEN 0 4096 *:7080 *:* users:(("dgraph",pid=2345,fd=9))
LISTEN 0 4096 *:8080 *:* users:(("dgraph",pid=2345,fd=10))
LISTEN 0 4096 *:9080 *:* users:(("dgraph",pid=2345,fd=11))
Test the Alpha health endpoint to confirm it joined the cluster successfully:
curl http://localhost:8080/health
A healthy response returns JSON showing the instance is “up” and “healthy”:
[{"instance":"zero","address":"localhost:5080","status":"healthy"},
{"instance":"alpha","address":"localhost:7080","status":"healthy","uptime":15}]
Step 4: Access Dgraph Ratel UI
Ratel is the web-based interface for Dgraph that lets you run queries, mutations, and visualize your graph data. Dgraph hosts Ratel as a standalone web application available at play.dgraph.io, which connects to your Alpha instance.
Open your browser and navigate to:
https://play.dgraph.io
In the Ratel interface, set the Dgraph server URL to your Alpha HTTP endpoint. If running locally, use:
http://localhost:8080
If accessing from a remote machine, replace localhost with your server’s IP address. Make sure port 8080 is open in your firewall (covered in Step 9).
Ratel provides three main panels – Query for running DQL queries, Mutate for inserting and modifying data, and Schema for managing your graph schema. The visualization panel renders query results as interactive graph diagrams.
Step 5: Define a Schema in Dgraph
Before inserting data, define a schema that tells Dgraph what predicates (fields) exist and what types of indexes to build. Without a schema, Dgraph stores data but cannot filter or sort on predicates efficiently.
Define a sample schema for a movie database with name, release date, and genre predicates. Send it to the /alter endpoint:
curl -X POST localhost:8080/alter -d '
name: string @index(exact, term) .
release_date: datetime @index(year) .
genre: [string] @index(exact) .
starring: [uid] @reverse .
director: [uid] @reverse .
type Movie {
name
release_date
genre
starring
director
}
type Person {
name
}
'
A successful response returns:
{"code":"Success","message":"Done"}
The schema defines:
name– a string with exact match and term (full-text) indexesrelease_date– a datetime indexed by year for range queriesgenre– a list of strings with exact match indexstarringanddirector– UID edges (relationships) with reverse index for traversing the graph in both directions
Verify the schema was applied by querying it back:
curl http://localhost:8080/query -d '
schema {}
' -H "Content-Type: application/dql"
Step 6: Mutate Data with DQL
Mutations insert or modify data in Dgraph. DQL mutations use JSON or RDF triple format to describe nodes and edges. Here we use JSON format to add movies and people to the graph.
Insert a movie with its director and cast:
curl -X POST localhost:8080/mutate?commitNow=true -H "Content-Type: application/json" -d '{
"set": [
{
"uid": "_:matrix",
"dgraph.type": "Movie",
"name": "The Matrix",
"release_date": "1999-03-31",
"genre": ["Sci-Fi", "Action"],
"director": [
{
"uid": "_:wachowski",
"dgraph.type": "Person",
"name": "Lana Wachowski"
}
],
"starring": [
{
"uid": "_:keanu",
"dgraph.type": "Person",
"name": "Keanu Reeves"
},
{
"uid": "_:laurence",
"dgraph.type": "Person",
"name": "Laurence Fishburne"
}
]
}
]
}'
The response includes the UIDs assigned to each new node. The _:matrix, _:keanu, etc. are blank node labels that Dgraph replaces with permanent UIDs:
{
"data": {
"code": "Success",
"message": "Done",
"uids": {
"keanu": "0x2",
"laurence": "0x3",
"matrix": "0x1",
"wachowski": "0x4"
}
}
}
Add another movie that shares an actor to build out the graph relationships:
curl -X POST localhost:8080/mutate?commitNow=true -H "Content-Type: application/json" -d '{
"set": [
{
"uid": "_:john_wick",
"dgraph.type": "Movie",
"name": "John Wick",
"release_date": "2014-10-24",
"genre": ["Action", "Thriller"],
"starring": [
{
"uid": "0x2",
"dgraph.type": "Person",
"name": "Keanu Reeves"
}
]
}
]
}'
Notice we reference Keanu Reeves by his existing UID (0x2) instead of creating a duplicate node. This is how you build connections between existing entities in the graph.
Step 7: Query Data with DQL
DQL (Dgraph Query Language) uses a GraphQL-like syntax to traverse and filter graph data. Queries go to the /query endpoint with Content-Type: application/dql.
Query all movies and their cast:
curl -s localhost:8080/query -H "Content-Type: application/dql" -d '{
movies(func: type(Movie)) {
uid
name
release_date
genre
starring {
name
}
director {
name
}
}
}' | python3 -m json.tool
The response returns all movies with their relationships expanded:
{
"data": {
"movies": [
{
"uid": "0x1",
"name": "The Matrix",
"release_date": "1999-03-31T00:00:00Z",
"genre": ["Sci-Fi", "Action"],
"starring": [
{"name": "Keanu Reeves"},
{"name": "Laurence Fishburne"}
],
"director": [
{"name": "Lana Wachowski"}
]
},
{
"uid": "0x5",
"name": "John Wick",
"release_date": "2014-10-24T00:00:00Z",
"genre": ["Action", "Thriller"],
"starring": [
{"name": "Keanu Reeves"}
]
}
]
}
}
Use a reverse edge to find all movies a specific person starred in:
curl -s localhost:8080/query -H "Content-Type: application/dql" -d '{
actor(func: eq(name, "Keanu Reeves")) {
name
~starring {
name
release_date
genre
}
}
}' | python3 -m json.tool
The ~starring syntax traverses the reverse edge, returning all movies where Keanu Reeves appears in the starring list. Filter queries with @filter to narrow results:
curl -s localhost:8080/query -H "Content-Type: application/dql" -d '{
sci_fi(func: type(Movie)) @filter(eq(genre, "Sci-Fi")) {
name
release_date
genre
}
}' | python3 -m json.tool
This returns only movies with the “Sci-Fi” genre. DQL supports a wide range of filter functions including eq, ge, le, has, allofterms, anyofterms, and regular expressions.
Step 8: Configure Dgraph as Systemd Services
For production use, run both Dgraph Zero and Alpha as systemd services so they start automatically on boot and restart on failure.
First, stop the background processes you started earlier:
pkill dgraph
Create a dedicated system user for Dgraph:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin dgraph
sudo chown -R dgraph:dgraph /var/lib/dgraph /var/log/dgraph
Create the Dgraph Zero systemd unit file:
sudo vi /etc/systemd/system/dgraph-zero.service
Add the following configuration:
[Unit]
Description=Dgraph Zero - Cluster Coordinator
After=network.target
[Service]
Type=simple
User=dgraph
Group=dgraph
ExecStart=/usr/local/bin/dgraph zero --wal /var/lib/dgraph/zero/zw --telemetry "reports=false;"
Restart=on-failure
RestartSec=10
StandardOutput=append:/var/log/dgraph/zero.log
StandardError=append:/var/log/dgraph/zero.log
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Create the Dgraph Alpha systemd unit file:
sudo vi /etc/systemd/system/dgraph-alpha.service
Add the following configuration:
[Unit]
Description=Dgraph Alpha - Data Server
After=network.target dgraph-zero.service
Requires=dgraph-zero.service
[Service]
Type=simple
User=dgraph
Group=dgraph
ExecStart=/usr/local/bin/dgraph alpha --zero localhost:5080 --postings /var/lib/dgraph/alpha/p --wal /var/lib/dgraph/alpha/w --tmp /var/lib/dgraph/alpha/t --telemetry "reports=false;"
Restart=on-failure
RestartSec=15
StandardOutput=append:/var/log/dgraph/alpha.log
StandardError=append:/var/log/dgraph/alpha.log
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Reload systemd, enable both services, and start them in order:
sudo systemctl daemon-reload
sudo systemctl enable dgraph-zero dgraph-alpha
sudo systemctl start dgraph-zero
Wait a few seconds for Zero to initialize, then start Alpha:
sudo systemctl start dgraph-alpha
Verify both services are running:
sudo systemctl status dgraph-zero dgraph-alpha
Both services should show active (running). Check the Alpha health endpoint to confirm the cluster is operational:
curl -s http://localhost:8080/health | python3 -m json.tool
Step 9: Configure Firewall for Dgraph
Dgraph uses five TCP ports across its two components. Open the ports you need based on whether you are running a single-node setup or a multi-node cluster.
| Port | Component | Purpose |
|---|---|---|
| 5080/tcp | Zero | Internal gRPC – Alpha-to-Zero communication |
| 6080/tcp | Zero | HTTP admin – cluster state and management |
| 7080/tcp | Alpha | Internal gRPC – Alpha-to-Alpha communication |
| 8080/tcp | Alpha | HTTP/GraphQL – queries, mutations, schema |
| 9080/tcp | Alpha | External gRPC – client connections |
On Ubuntu, use UFW (Uncomplicated Firewall) to open the required ports. For a single-node setup where clients connect remotely, open ports 8080 and 9080:
sudo ufw allow 8080/tcp comment "Dgraph Alpha HTTP/GraphQL"
sudo ufw allow 9080/tcp comment "Dgraph Alpha gRPC"
For a multi-node cluster, also open the internal communication ports between Dgraph nodes. Restrict these to your cluster network only:
sudo ufw allow from 10.0.1.0/24 to any port 5080 proto tcp comment "Dgraph Zero gRPC"
sudo ufw allow from 10.0.1.0/24 to any port 6080 proto tcp comment "Dgraph Zero HTTP"
sudo ufw allow from 10.0.1.0/24 to any port 7080 proto tcp comment "Dgraph Alpha internal gRPC"
Replace 10.0.1.0/24 with your actual cluster subnet. Reload UFW and verify the rules:
sudo ufw reload
sudo ufw status numbered
The output lists all active rules with their port assignments and source restrictions:
Status: active
To Action From
-- ------ ----
[ 1] 8080/tcp ALLOW IN Anywhere # Dgraph Alpha HTTP/GraphQL
[ 2] 9080/tcp ALLOW IN Anywhere # Dgraph Alpha gRPC
[ 3] 5080/tcp ALLOW IN 10.0.1.0/24 # Dgraph Zero gRPC
[ 4] 6080/tcp ALLOW IN 10.0.1.0/24 # Dgraph Zero HTTP
[ 5] 7080/tcp ALLOW IN 10.0.1.0/24 # Dgraph Alpha internal gRPC
Step 10: Backup and Restore Dgraph Data
Dgraph supports online backups through its admin GraphQL endpoint. Backups capture the full cluster state including schema, data, and ACL information without taking the cluster offline.
Create a Backup
Create a backup directory and set the proper permissions:
sudo mkdir -p /var/backups/dgraph
sudo chown dgraph:dgraph /var/backups/dgraph
Trigger a full backup using the admin endpoint. Dgraph Alpha must be configured to allow the backup path by setting the --export flag or using the default path:
curl -s localhost:8080/admin -H "Content-Type: application/json" -d '{
"query": "mutation { export(input: {format: \"json\"}) { response { message } } }"
}' | python3 -m json.tool
A successful export returns a confirmation message with the export path:
{
"data": {
"export": {
"response": {
"message": "Export completed."
}
}
}
}
The export files are stored in the Alpha data directory under an export folder with a timestamped directory name. List the exported files:
ls -la /var/lib/dgraph/alpha/export/
Copy the export directory to your backup location for safekeeping:
sudo cp -r /var/lib/dgraph/alpha/export/* /var/backups/dgraph/
Restore from Backup
To restore data from an export, use the dgraph live command to load the exported JSON or RDF files into a running cluster. Make sure Zero and Alpha are both running before starting the restore.
First, restore the schema:
dgraph live -s /var/backups/dgraph/dgraph.schema.gz \
-f /var/backups/dgraph/g01.json.gz \
-a localhost:9080 \
-z localhost:5080
The -s flag points to the schema file, -f to the data file, -a to the Alpha gRPC address, and -z to the Zero gRPC address. The restore process loads all nodes and edges back into the database.
Verify the restore by running a test query against the data:
curl -s localhost:8080/query -H "Content-Type: application/dql" -d '{
check(func: has(name), first: 5) {
uid
name
dgraph.type
}
}' | python3 -m json.tool
For automated backups, add a cron job that runs the export daily. If you manage MongoDB or other NoSQL databases alongside Dgraph, schedule backups at staggered times to avoid I/O contention.
Conclusion
You now have Dgraph v25.3.0 running on Ubuntu 24.04 with Zero and Alpha configured as systemd services, a defined schema, sample data loaded, and firewall rules in place. The setup handles queries, mutations, and exports out of the box.
For production hardening, configure TLS encryption between Zero and Alpha nodes, set up ACL (Access Control Lists) to restrict database access, deploy multiple Zero and Alpha instances for high availability, and ship the Dgraph logs to a centralized monitoring stack for alerting on cluster health.