Self-hosted service
target/goalert avatar
target/goalert

GoAlert: on-call scheduling and escalation in a single Go binary

Open source on-call scheduling, automated escalations, and notifications so you never miss a critical alert

2,834 stars327 forksGoApache-2.0

At a glance

What is it?
Target's GoAlert routes alerts to the right person over SMS, voice or chat and escalates when nobody answers. It ships as one binary or a Docker image, and the demo container is the fastest way to see how the escalation engine behaves.
Who is it for?
Adopt GoAlert if you want the escalation ladder, on-call rotations and notification fan-out to live in one process you can run from a single binary or a Docker image, and you are willing to run PostgreSQL next to it. Do not adopt it if you need a hosted service with no database to operate, or if you cannot give it working SMS and voice credentials, because the escalation path is only as good as the contact methods behind it.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 8 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What GoAlert solves, and who ends up running it

An alert that fires into a shared inbox is not an escalation policy. Someone has to decide who is on call right now, how long to wait before trying the next person, and which channel to use at 3am. GoAlert exists to make that decision mechanical. The README describes it as on-call scheduling, automated escalations and notifications (like SMS or voice calls), with the stated goal of engaging "the right person, the right way, and at the right time".

The audience is operations and platform teams that already have monitoring producing alerts and want the human routing layer to be something they control. Because it is distributed as a single binary and as Docker images, the deployment model suits teams that run their own infrastructure rather than buying a paging SaaS. The repository layout backs that up: there are packages for assignment, escalation, heartbeat, alert, calsub and apikey, so the domain is broken into scheduling, escalation and inbound alert handling rather than being one monolith of handlers.

It is a poor fit for a team with no operational capacity at all. GoAlert is software you run, and the parts that matter (the database, the notification providers, the network path to your monitoring) are yours to keep working.

The escalation engine and the pieces around it

The mechanism visible from the repository is a Go service backed by PostgreSQL. The Makefile defines DB_URL as postgres://goalert@localhost:5432/goalert and the development database is versioned with migrations run through a goalert-migrate tool, so schema changes are part of the project's own workflow rather than something left to the operator.

Alert intake is separated from notification. The alert/ and integrationkey/ packages handle inbound alerts and the keys that authenticate them, which is what a monitoring system uses to open an incident. The escalation/ and assignment/ packages decide who is next, and heartbeat/ covers the case where a system is expected to check in and should page when it stops. Notification delivery is not a single code path: go.mod lists github.com/emersion/go-smtp for mail, github.com/slack-go/slack for Slack, and github.com/nyaruka/phonenumbers, which is the library you reach for when phone numbers have to be parsed and formatted per country before an SMS or voice call is attempted. The presence of go-oidc and oauth2-proxy/mockoidc points at OIDC-based login alongside the local basic auth the demo uses.

Background work is queued rather than fired inline. The dependency list includes the river job queue with both a database/sql driver and a pgx driver, plus pgxlisten, so jobs are persisted in PostgreSQL and workers are woken by LISTEN/NOTIFY. That is a deliberate design choice with a consequence worth naming: the queue lives in the same database as the scheduling data, so a database that is unavailable stops both the schedule and the delivery of the pages it produced.

Running the GoAlert demo container and logging in

The README's quick start is a single command. It pulls the demo image, publishes port 8081, and removes the container when it exits.

bash
docker run -it --rm -p 8081:8081 goalert/demo

After that, the README states GoAlert is running at localhost:8081 and you log in with admin/admin123. The demo container is seeded with data, which is why the UI has something to show on first load.

If you are wiring the demo into an integration test rather than clicking around, the README documents two extra details. A non-admin account exists as user/user1234, and setting the environment variable SKIP_SEED=1 skips the initial seed step so you start from an empty instance. To get a session token without a browser, the README gives this curl invocation:

bash
curl -XPOST -H 'Referer: http://localhost:8081' \
  -d 'username=admin&password=admin123' \
  'http://localhost:8081/api/v2/identity/providers/basic?noRedirect=1'

The Referer header is not decoration here; the README includes it in the example, so keep it when you adapt the call. For anything beyond a demo, the README points at docs/getting-started.md for running GoAlert in a production environment rather than describing that topology itself.

Contributors get a different entry point. From the repository root, make start brings up a development server on http://localhost:3030 with the same admin/admin123 login, and the README says local UI and backend changes are reflected in the running server within a few seconds without a restart.

Where GoAlert stops being the right tool

The most concrete limitation is that the demo image is not the product. The README explicitly separates the quick start from the Getting Started Guide for production, which means the interesting questions (database sizing, TLS termination, backup, how the binary is supervised) are answered somewhere other than the front page. If you evaluate GoAlert by running the demo container and nothing else, you have evaluated the UI, not the deployment.

Notification delivery depends on external providers. The code pulls in SMTP, Slack and phone-number handling libraries, but the README does not document which providers are configured out of the box or what credentials each requires. That is a real gap for anyone budgeting the work: SMS and voice in particular usually mean a paid gateway, and the escalation policy is only as reliable as that gateway.

Operationally, PostgreSQL is not optional. The queue, the schedule and the migration state all live there, and the Makefile's own defaults assume a local Postgres on 5432. Teams that have standardized on a managed queue and a document store will be adding a stateful component they now have to run, monitor and restore.

Finally, GoAlert is an escalation router, not an observability platform. It does not appear to store or query metrics and logs; it receives alerts and gets people moving. If what you actually need is dashboards over time-series data with paging bolted on, this is the wrong layer.

GoAlert compared with a hosted paging service

The honest alternative is a hosted incident and paging service, where the vendor runs the scheduler, the phone gateway and the database, and you pay per user. The difference is not features so much as who owns the failure modes. With GoAlert you own the PostgreSQL instance, the process supervision and the notification credentials; in exchange, the escalation logic, the schedule data and the audit trail stay inside your network, and there is no per-seat meter to argue about.

The second alternative is building the routing yourself on top of your existing alerting stack. That is cheaper only if the schedule is trivial. Once you need rotations, overrides, a multi-step escalation ladder and a record of who was paged and when, you are reimplementing the packages this repository already contains. The trade-off is that a self-built router fits your existing deployment model exactly, whereas GoAlert asks you to adopt its database and its release cadence.

A fair way to frame the choice: pick GoAlert when control of the paging path matters more than having someone else on the hook for it, and pick a hosted service when nobody on the team wants to be the person who restores the paging database during an incident.

Licence, releases and what upgrades cost you

GoAlert is licensed under the Apache License, Version 2.0, and the README links the full text at LICENSE.md. Apache-2.0 is a permissive licence with an explicit patent grant, which generally makes it straightforward to run internally or embed in a commercial product. It also means there is no copyleft obligation to publish your modifications. That is a description of the licence text, not legal advice; if you are redistributing GoAlert or modifying it as part of a product, have counsel read LICENSE.md.

The release cadence is uneven, and that shapes upgrade planning. v0.34.0 landed on 2025-08-28, v0.34.1 on 2025-10-06, and v0.35.0 on 2026-09-21, roughly a year after the previous minor. The repository's last push was on 2026-09-23, so work continues between releases, but you should not plan around a monthly train. The project ships a nightly image built from master in addition to the latest tag, which is useful for testing ahead of a release and unsuitable as a production default.

Upgrade cost is dominated by the database. The Makefile carries migration tooling and a new-migration target, and the development setup resets and regenerates the schema, which tells you schema changes are expected between versions rather than exceptional. Budget for a database backup and a migration run on every version bump, and read the release notes on the GitHub Releases page before you take one, since that is where the README points for release information.

Editorial conclusion

Adopt GoAlert if you want the escalation ladder, on-call rotations and notification fan-out to live in one process you can run from a single binary or a Docker image, and you are willing to run PostgreSQL next to it. Do not adopt it if you need a hosted service with no database to operate, or if you cannot give it working SMS and voice credentials, because the escalation path is only as good as the contact methods behind it. Before committing, open the Getting Started Guide in docs/ and confirm the production topology it describes matches what you can run, then verify which notification methods your deployment can actually reach.

Frequently asked questions

What is GoAlert?

GoAlert is an open source tool for on-call scheduling, automated escalations and notifications such as SMS or voice calls. It is written in Go, licensed under Apache-2.0, and distributed as a single binary and as Docker images.

What is a GoAlert alternative?

The realistic alternative is a hosted paging service that runs the scheduler and phone gateway for you, or building the routing on top of your existing alerting stack. GoAlert differs in that you run the service and its PostgreSQL database yourself, so the escalation logic and schedule data stay inside your network.

How do I try GoAlert without installing it?

The README gives a demo container that runs with docker run -it --rm -p 8081:8081 goalert/demo. GoAlert then serves at localhost:8081 and you log in with admin/admin123.

Does GoAlert need a database?

Yes. The Makefile defaults to postgres://goalert@localhost:5432/goalert, and the job queue used for background work is backed by PostgreSQL as well. The README directs production setups to docs/getting-started.md rather than the demo command.

How do I get a GoAlert session token for API testing?

The README documents a curl call against /api/v2/identity/providers/basic?noRedirect=1 with a Referer header of http://localhost:8081 and the username and password form fields. It is described specifically for the demo container.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. target/goalert on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/target-goalert.svg)](https://hysenlabs.com/projects/target-goalert)