Hook
You deploy a new version at 2:47 PM, and three minutes later your API response times spike by 40%. Was it the deploy? You stare at your Grafana dashboard, squinting at timestamps, trying to correlate the release with the metric. Deployment annotations solve this problem by embedding release information directly into your graphs, so you see exactly when code changes hit production and can instantly spot the culprit.
Why deployment annotations matter
Deployment annotations: a practical guide for developers starts with understanding why this matters. In a typical incident, you're racing against the clock. Your on-call engineer is looking at CPU, latency, error rates, and queue depth. Without annotations, they're playing detective with timestamps. With annotations, the graph screams: "Version 2.3.1 shipped here, and everything went sideways 90 seconds later."
We've seen teams save 10–15 minutes per incident just by having visible annotations. That's not trivial when you're hemorrhaging requests. More importantly, it removes guesswork from your post-mortems. Instead of debating whether the deploy caused the issue, you have visual proof.
Annotate dashboards on deploy
Grafana annotations are metadata events overlaid on your time series graphs. They're vertical lines or text labels that mark significant moments: deployments, config changes, incidents, or even manual interventions.
The simplest approach is to tag your metrics at deploy time. When your CI/CD pipeline finishes a deployment, you fire an annotation to Grafana. Most teams use a few key fields:
- Time: when the deployment occurred
- Tags: environment (prod, staging), service name, team
- Text: short description—commit hash, version number, or a link
Let's walk through a real example. Your deployment pipeline completes. You've just pushed version 3.2.0 of your order-service to production. Instead of just logging "Deployment succeeded," you send an annotation to Grafana with the version, commit hash, and a link to your release notes.
Six hours later, when that graph shows a performance cliff, everyone looking at the dashboard instantly sees the annotation. They know exactly what changed and when.
Grafana annotations API from CI
Grafana exposes an HTTP API for creating annotations. Your CI/CD system (GitHub Actions, GitLab CI, Jenkins, whatever) can call it directly.
Here's what a basic annotation request looks like:
POST /api/annotations HTTP/1.1
Host: grafana.example.com
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
{
"dashboardId": 123,
"panelId": 4,
"tags": ["deployment", "order-service", "prod"],
"text": "Deployed v3.2.0 (commit: abc1234)",
"time": 1704067200000
}
In practice, you'll want to call this from your deployment script. Here's a typical pattern in a GitHub Actions workflow:
- name: Create Grafana Annotation
if: success()
run: |
curl -X POST https://grafana.example.com/api/annotations \
-H "Authorization: Bearer ${{ secrets.GRAFANA_API_TOKEN }}" \
-H "Content-Type: application/json" \
-d '{
"dashboardId": 123,
"tags": ["deployment", "order-service", "prod"],
"text": "Deployed v${{ github.ref_name }} (${{ github.sha }})",
"time": '$(date +%s000)'
}'
A few practical notes:
- Time format: Grafana expects milliseconds since epoch, not seconds. That trailing "000" is easy to forget.
- Dashboard ID: You can hardcode this, or look it up by slug using
/api/dashboards/db/{slug}. - Tags: Use consistent tags across your team. "deployment", "canary", "rollback" become queryable later.
- API token: Create one with admin or editor access in Grafana. Store it as a secret in your CI system.
Some teams go further and include structured data in the text field:
{
"text": "v3.2.0 | Author: alice@company.com | PR: #4521 | Changelog: bit.ly/release-notes"
}
That way, on-call engineers get context without leaving the dashboard.
Compare before and after
The real power of annotations emerges when you're doing incident analysis. Pull up your main service dashboard. Look at error rates, latency, CPU, disk I/O. Without annotations, you're correlating timestamps manually. With them, you see the annotation, and it's obvious what changed.
Let's say you see this pattern:
- Error rate flat at 0.2% for 2 hours
- Deployment annotation at 14:47
- Error rate jumps to 3.5% at 14:48
- Rollback annotation at 15:02
- Error rate drops back to 0.2% at 15:03
That's a smoking gun. You deployed, errors spiked, you rolled back, errors recovered. The deployment broke something.
Now compare that to a healthier scenario:
- Deployment annotation at 09:15
- Error rate stays flat
- P95 latency improves slightly
- Nothing else happens
Good deploy. Move on.
The visual correlation is immediate. No spreadsheets, no timestamps, no debate. This is why many teams make annotations mandatory in their incident playbooks: before you reach for your rollback button, look at the dashboard. Is the annotation recent? Yes? Probably the deploy.
Spot bad releases instantly
Annotations also serve as an early warning system. If you deploy every 15 minutes, you'll see a vertical line every 15 minutes. If you notice that every annotation is followed by a small blip in error rate or latency, you have a systemic problem—maybe your deployment process is creating brief traffic disruptions, or your health checks are too lenient.
Some teams set up Grafana alerts that fire *on* annotations. For example: "If an annotation with tag 'deployment' is created, and error rate rises more than 2x within 5 minutes, page the on-call engineer." That's more aggressive, but it catches regressions within seconds.
Others use annotations as a post-hoc analysis tool. After an incident, you pull the dashboard spanning the last 24 hours. You see all deployments, all alerts, all manual interventions. You spot patterns: "Every time Alice's team deploys, we see database connection pool exhaustion 10 minutes later." That's feedback for their code review process.
In one real incident we handled, a team noticed that deployments were consistently followed by a 30-second CPU spike. It looked like noise at first—recovers quickly, no errors, users don't notice. But when you stack five deployments an hour for six hours, those tiny spikes add up. Annotations made the pattern visible. Turned out they had a memory leak in their initialization code. Would have taken weeks to find without that visual feedback.
Common mistakes
Not setting the timezone correctly. Grafana stores times in UTC. If your CI system is in a different timezone and you don't convert, your annotations will appear at the wrong time. Always convert to epoch milliseconds, which is timezone-agnostic.
Creating too many annotations. Every commit? Every test run? Your dashboard becomes noise. Annotate production deployments, major config changes, and incidents. Not every CI job.
Forgetting to clean up old annotations. Grafana keeps them indefinitely. Over a year, you can accumulate thousands. Set up a retention policy or periodically prune annotations older than, say, 90 days.
Not including enough context. "Deployed" tells you nothing. Include version, commit hash, link to release notes, and who deployed it. That's the difference between "we shipped something" and "we shipped v3.2.0 with the new caching layer, PR #4521."
Annotating only one dashboard. If you only annotate your main service dashboard but not your database, cache, or load balancer dashboards, you'll miss downstream effects. Annotate all critical dashboards with the same deployment event.
Key takeaways
- Annotations embed release information directly into graphs, eliminating guesswork during incidents and post-mortems.
- Grafana's HTTP API lets you create annotations from your CI/CD pipeline with a simple curl or SDK call.
- Include version, commit hash, and context in annotation text so on-call engineers have actionable information without leaving the dashboard.
- Use consistent tags (deployment, rollback, canary) to make annotations queryable and analyzable over time.
- Always convert to epoch milliseconds in UTC to avoid timezone mismatches.
- Annotate production deployments and major changes, not every CI job, to keep dashboards readable.
- Annotations on multiple related dashboards reveal the full impact of a deployment across your system.






Comments
Loading comments…