In modern Linux operating systems powered by systemd, managing startup order and service prerequisites involves complex dependency relationships. Unit files express these relationships through directives such as Requires=, Wants=, After=, Before=, BindsTo=, and PartOf=. While declarative dependencies allow systemd to parallelize service execution aggressively during boot, deeply nested or conflicting relationships can introduce circular dependency deadlocks, unexpected service terminations, or boot bottlenecks.
Inspecting complex service topologies using traditional text-based commands such as systemctl list-dependencies becomes unwieldy when troubleshooting dozens of interconnected microservices, database clusters, or container runtimes. To provide comprehensive visual observability, systemd includes a built-in graph generation utility: systemd-analyze dot. This tool parses the active system dependency database and outputs the complete graph structure in standard Graphviz DOT format, allowing Ubuntu administrators to render high-resolution, navigable visual graphs of service hierarchies.
Understanding systemd Dependency Types and Graph Semantics
When systemd constructs its internal dependency directed acyclic graph (DAG), it tracks two orthogonal types of relationships:
- Requirement Dependencies (Requires, Wants, BindsTo): Define activation semantics. For example,
Requires=database.servicespecifies that if the parent unit starts, the database must also start; if the database fails, the parent unit stops.Wants=establishes a soft, non-fatal preference. - Ordering Dependencies (After, Before): Define temporal execution order. Ordering directives do not imply activation; they simply declare that if both units happen to be scheduled, unit A must transition to active before unit B starts.
In a generated dependency diagram, Graphviz renders these relationships using distinct edge styling:
- Black solid arrows: Represent hard requirement dependencies (
Requires=). - Black dashed arrows: Represent soft activation dependencies (
Wants=). - Red solid arrows: Represent ordering constraints (
After=/Before=). Circular loops in red arrows indicate illegal ordering loops that systemd must break automatically at boot.
Installing Graphviz on Ubuntu
The systemd-analyze dot command outputs raw DOT language text streams. To convert these text streams into viewable SVG or PNG images, ensure that the Graphviz visualization suite is installed on Ubuntu:
# Update package repositories and install Graphviz
sudo apt update
sudo apt install -y graphviz
Generating a Dependency Graph for a Specific Service
Running systemd-analyze dot without arguments generates a graph containing every unit, socket, target, and device on the entire operating system, resulting in an overwhelming diagram with tens of thousands of nodes. In practice, you should always target specific services or filter by pattern using standard globbing syntax.
To generate and render an SVG dependency diagram for a specific daemon (such as Nginx):
# Generate an SVG dependency diagram for nginx.service
systemd-analyze dot 'nginx.service' | dot -Tsvg -o nginx-dependencies.svg
Open the resulting nginx-dependencies.svg in any web browser or image viewer. The diagram displays the complete upstream and downstream dependency chain connected to Nginx, including network targets, system sockets, and mount dependencies.
Filtering by Pattern and Target Boundaries
To analyze relationships across multiple related services (for example, all container or database daemons) without including standard low-level system slices:
# Filter by pattern and exclude basic system slice noise
systemd-analyze dot --to-pattern='*.target' --from-pattern='docker*.service' | dot -Tsvg -o docker-targets.svg
You can also inspect how high-level boot targets transition during initialization:
# Visualize dependencies between major boot targets
systemd-analyze dot 'multi-user.target' | dot -Tsvg -o multi-user-target.svg
Diagnosing and Resolving Circular Dependency Loops
Circular dependencies occur when service A requires service B to start After=B, while service B (or one of its transitive dependencies) requires service A to start After=A. When this happens, systemd logs an error during boot (Found ordering cycle on ...) and forcibly drops an arbitrary unit from the transaction to avoid an infinite loop.
To specifically isolate ordering dependencies and detect circular loops visually:
# Generate an ordering-only graph to expose dependency cycles
systemd-analyze dot --order | grep -E "color=\"red\"" | dot -Tsvg -o ordering-cycles.svg
Inspect the output SVG for closed loop cycles. Once identified, edit the offending unit file or drop-in configuration in /etc/systemd/system/ to remove the redundant After= or Before= directive.
Automating Dependency Visualizations for System Documentation
In automated infrastructure pipelines, you can incorporate graph generation into documentation workflows to maintain up-to-date architectural topology maps:
#!/usr/bin/env bash
set -euo pipefail
DOCS_DIR="/var/www/html/docs/architecture"
mkdir -p "${DOCS_DIR}"
SERVICES=("nginx.service" "postgresql.service" "redis-server.service")
for SVC in "${SERVICES[@]}"; do
echo "Rendering graph for ${SVC}..."
systemd-analyze dot "${SVC}" | dot -Tsvg -o "${DOCS_DIR}/${SVC}.svg"
done
echo "Architecture diagrams generated successfully in ${DOCS_DIR}"
Using systemd-analyze dot provides system engineers on Ubuntu with instant visual clarity over complex unit hierarchies, accelerating troubleshooting and optimizing system boot performance.