How to Set Up Prometheus with Grafana-Style Alerting via Alertmanager
Prometheus evaluates alert rules locally but never sends a notification - that is Alertmanager's job. To wire the two together you add a top-level alerting: block to prometheus.yaml pointing at Alertmanager on localhost:9093, write a minimal alertmanager.yaml with one webhook receiver, and run both binaries side by side. Here is the full setup, with a synthetic 5xx spike to prove the alert lands.
Why Prometheus alone never pages you
Prometheus loads your alert rules and evaluates them every evaluation_interval, but
a firing rule only becomes a row in Prometheus's own /api/v1/alerts. Prometheus does
not group, deduplicate, or route notifications - it fans every firing alert out over
HTTP as POST /api/v2/alerts to each Alertmanager it is told about. If you never
configure an Alertmanager, alerts fire silently and no one is paged.
So the setup has two moving parts: tell Prometheus where Alertmanager is, and stand up an Alertmanager that knows what to do with the alerts it receives. This is the same Prometheus + alerting stack you pair with Grafana for dashboards - Grafana reads Prometheus, Alertmanager routes the pages.
Step 1 - add the alerting block to prometheus.yaml
alerting: is a top-level key, a peer of scrape_configs: and rule_files: - not
nested under them. The minimum is a static target pointing at Alertmanager:
global:
scrape_interval: 2s
evaluation_interval: 5s
rule_files:
- alerts.yaml
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']
scrape_configs:
- job_name: 'api'
static_configs:
- targets: ['localhost:8000']
Nesting alerting: inside scrape_configs: is the most common mistake and Prometheus
will simply ignore it - /api/v1/alertmanagers will show zero active peers.
Step 2 - write a minimal alertmanager.yaml
An Alertmanager config is a route: (how alerts flow) plus receivers: (where they
go). One webhook receiver is enough to prove the pipe:
route:
receiver: webhook
group_wait: 1s
group_interval: 1s
repeat_interval: 1m
receivers:
- name: webhook
webhook_configs:
- url: http://localhost:5001/sink
send_resolved: false
Validate it before starting anything - amtool catches indentation and schema errors:
amtool check-config alertmanager.yaml
The webhook does not have to actually accept the POST. Alertmanager tries, fails, retries in the background, and the alert still shows as active in its API - which is exactly what you verify at the end.
Step 3 - run both binaries side by side
alertmanager --config.file=alertmanager.yaml --storage.path=/tmp/am --web.listen-address=:9093 &
prometheus --config.file=prometheus.yaml --storage.tsdb.path=/tmp/prom --web.listen-address=:9090 &
Confirm Prometheus discovered the Alertmanager - activeAlertmanagers should be 1:
curl http://localhost:9090/api/v1/alertmanagers | python3 -m json.tool
Step 4 - drive a synthetic failure and verify
The demo app exposes a /flag/fail toggle and an /api/maybe-fail endpoint that starts
returning 500s once flipped. The HighErrorRate rule fires when the 5xx ratio crosses
1% for 5 seconds:
curl -X POST http://localhost:8000/flag/fail
for i in {1..30}; do curl -s http://localhost:8000/api/maybe-fail >/dev/null; done
Give Prometheus a couple of evaluation cycles, then confirm the alert reached Alertmanager end to end:
curl http://localhost:9093/api/v2/alerts | python3 -m json.tool
You should see a HighErrorRate entry with status.state active - proof the full path
fired, forwarded, and landed.
Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.
Try it in a workspace →What you'll practice
- Adding a top-level alerting block to prometheus.yaml that targets Alertmanager on port 9093
- Authoring and validating a minimal alertmanager.yaml with amtool check-config
- Confirming an alert traversed the stack via /api/v1/alertmanagers and /api/v2/alerts
FAQ
How do I connect Prometheus to Alertmanager?
Add a top-level alerting: block to prometheus.yaml with alertmanagers.static_configs.targets set to Alertmanager's host:port (e.g. localhost:9093). It sits beside scrape_configs, not inside it. After reload, /api/v1/alertmanagers should list one active Alertmanager.
Why is Prometheus not sending alerts to Alertmanager?
Prometheus only forwards alerts to Alertmanagers listed in its alerting: block, and that block must be a top-level key - nesting it under scrape_configs makes Prometheus silently ignore it. Check /api/v1/alertmanagers; if activeAlertmanagers is empty, the alerting config is missing or misplaced.
How do I test that an alert reaches Alertmanager?
Drive the condition your rule watches (for example spike the 5xx rate), wait a few evaluation intervals, then query Alertmanager at /api/v2/alerts. A firing alert appears there even if the downstream receiver webhook is unreachable, because Alertmanager retries delivery in the background.
Do I need Grafana to use Prometheus alerting?
No. Prometheus evaluates rules and Alertmanager routes the notifications entirely without Grafana. Grafana adds dashboards on top of the same Prometheus data and can define its own alerts, but the Prometheus + Alertmanager pair is the standalone alerting backbone.
Keep learning
Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.
Open the workspace →