# How the Uptime Kuma Monitoring System Works Internally: Architecture and Code Deep Dive

> Discover the internal workings of Uptime Kuma. Learn how this Node.js monitoring system uses SQLite, Socket.io, and croner for efficient health checks and real-time alerts.

- Repository: [Louis Lam/uptime-kuma](https://github.com/louislam/uptime-kuma)
- Tags: internals
- Published: 2026-02-28

---

**Uptime Kuma operates as a Node.js producer-consumer pipeline that schedules health checks via the croner package, stores results in SQLite, broadcasts real-time updates through Socket.io, and dispatches alerts when monitor statuses change.**

Uptime Kuma is an open-source Node.js application (available at `louislam/uptime-kuma`) that continuously monitors the health of websites, services, and network endpoints. The **Uptime Kuma monitoring system** combines a SQLite database for persistence, a job scheduler for check coordination, and a real-time event bus for instant status updates. Understanding its internal workflow requires examining the model layer in `server/model/`, the scheduler in [`server/jobs.js`](https://github.com/louislam/uptime-kuma/blob/main/server/jobs.js), and the notification pipeline in [`server/notification.js`](https://github.com/louislam/uptime-kuma/blob/main/server/notification.js).

## Monitor Definition and Job Scheduling

Every monitored resource is represented by a row in the `monitor` table and instantiated as a `Monitor` model in [`server/model/monitor.js`](https://github.com/louislam/uptime-kuma/blob/main/server/model/monitor.js). The model encapsulates the check interval (in seconds) or a custom cron expression that determines when the monitor executes.

The scheduler lives in [`server/jobs.js`](https://github.com/louislam/uptime-kuma/blob/main/server/jobs.js) and utilizes the **croner** npm package to create jobs for every active monitor. When a monitor uses an interval, the system translates seconds into a cron pattern; otherwise, it uses the user-defined cron string.

```javascript
// Creating a monitor (used by the API route in server/routers/api-router.js)
const monitor = await Monitor.add({
    name: "My Site",
    type: "http",
    interval: 60,               // every minute
    url: "https://example.com",
    httpMethod: "GET",
    authUser: "",
    authPass: "",
    body: "",
    headers: {}
});

```

```javascript
// From server/jobs.js – registers a job for each monitor
const scheduleMonitor = (monitor) => {
    const pattern = monitor.interval
        ? `*/${monitor.interval} * * * * *`   // every N seconds
        : monitor.cron;                      // custom cron
    const job = new Cron(pattern, async () => {
        await monitor.run();                // dispatches to the monitor‑type
    });
    monitorJobMap.set(monitor.id, job);
};

```

## Protocol-Specific Monitor Types

When a scheduled job fires, [`server/model/monitor.js`](https://github.com/louislam/uptime-kuma/blob/main/server/model/monitor.js) dynamically loads the appropriate implementation from `server/monitor-types/` based on the monitor's `type` property. Each type class exposes a `ping` method that receives a client instance (such as a `got` HTTP client or Globalping instance) and returns a **heartbeat** object containing `status`, `msg`, `ping` (ms), and TLS information.

```javascript
// Core monitor execution (server/model/monitor.js)
async run() {
    const typeClass = require(`../monitor-types/${this.type}`);
    const monitorType = new typeClass(this);
    const hb = await monitorType.ping(); // returns {status, msg, ping, …}
    await hb.save();                     // persists to DB
    io.to(this.user_id).emit("heartbeat", hb.toJSON()); // real‑time push
}

```

Specific implementations include:

- **HTTP/HTTPS** ([`server/monitor-types/http.js`](https://github.com/louislam/uptime-kuma/blob/main/server/monitor-types/http.js)): Performs requests with optional headers, authentication, and redirect following.
- **ICMP Ping** ([`server/monitor-types/ping.js`](https://github.com/louislam/uptime-kuma/blob/main/server/monitor-types/ping.js)): Executes system ping commands or utilizes the Globalping service for distributed checks.
- **TCP, DNS, MongoDB, MQTT** ([`server/monitor-types/tcp.js`](https://github.com/louislam/uptime-kuma/blob/main/server/monitor-types/tcp.js), [`dns.js`](https://github.com/louislam/uptime-kuma/blob/main/dns.js), [`mongodb.js`](https://github.com/louislam/uptime-kuma/blob/main/mongodb.js), [`mqtt.js`](https://github.com/louislam/uptime-kuma/blob/main/mqtt.js)): Each encapsulates protocol-specific handshake or query logic.

## Heartbeat Persistence and Uptime Calculation

After a monitor type generates a heartbeat, the result is persisted to the `heartbeat` table via [`server/model/heartbeat.js`](https://github.com/louislam/uptime-kuma/blob/main/server/model/heartbeat.js). The [`uptime-calculator.js`](https://github.com/louislam/uptime-kuma/blob/main/uptime-calculator.js) module subsequently aggregates these rows to compute uptime percentages, average response times, and downtime periods across arbitrary time windows.

This separation of concerns allows the check execution to remain lightweight while background processes handle statistical analysis. The heartbeat records maintain foreign key relationships to their parent monitors, enabling efficient historical queries through the REST API defined in [`server/routers/api-router.js`](https://github.com/louislam/uptime-kuma/blob/main/server/routers/api-router.js).

## Real-Time Communication and Notification Pipeline

Uptime Kuma employs **Socket.io** to push updates to connected dashboards immediately upon heartbeat insertion. The [`server/socket-handlers/monitor-socket-handler.js`](https://github.com/louislam/uptime-kuma/blob/main/server/socket-handlers/monitor-socket-handler.js) file manages the `heartbeat` event emission, ensuring the Vue-based UI reflects status changes without polling.

Simultaneously, the notification engine in [`server/notification.js`](https://github.com/louislam/uptime-kuma/blob/main/server/notification.js) evaluates whether the new heartbeat represents a status transition (e.g., from **UP** to **DOWN**). When a transition occurs, the system iterates through all enabled notification providers in `server/notification-providers/` (such as [`telegram.js`](https://github.com/louislam/uptime-kuma/blob/main/telegram.js) or [`slack.js`](https://github.com/louislam/uptime-kuma/blob/main/slack.js)) and dispatches formatted messages.

```javascript
// Notification trigger (server/notification.js)
if (previous.status !== hb.status) {          // status change detected
    for (const n of await this.getEnabledNotifications(this.id)) {
        await NotificationProvider.send(
            n,
            `Monitor ${this.name} is now ${hb.status}`,
            this.toPublicJSON(),
            hb.toPublicJSON()
        );
    }
}

```

## Maintenance Windows and External Integration

**Maintenance Mode** functionality resides in [`server/model/maintenance.js`](https://github.com/louislam/uptime-kuma/blob/main/server/model/maintenance.js), which schedules suppression windows using separate croner jobs. While active, these windows inhibit alert generation for affected monitors, preventing false-positive notifications during planned downtime.

For external observability, [`server/prometheus.js`](https://github.com/louislam/uptime-kuma/blob/main/server/prometheus.js) implements a Prometheus exporter that aggregates recent heartbeat data and exposes it at the `/metrics` endpoint. This allows external monitoring systems to scrape Uptime Kuma's internal health metrics. The main server entry at [`server/uptime-kuma-server.js`](https://github.com/louislam/uptime-kuma/blob/main/server/uptime-kuma-server.js) bootstraps Express, Socket.io, and the job scheduler to coordinate these components.

## Summary

- **Uptime Kuma** orchestrates health checks through a Node.js scheduler that instantiates protocol-specific classes from `server/monitor-types/` to execute pings.
- The **croner** package drives the scheduling engine in [`server/jobs.js`](https://github.com/louislam/uptime-kuma/blob/main/server/jobs.js), supporting both interval-based and cron-based execution patterns.
- Check results are stored as **heartbeats** in SQLite via [`server/model/heartbeat.js`](https://github.com/louislam/uptime-kuma/blob/main/server/model/heartbeat.js), with [`uptime-calculator.js`](https://github.com/louislam/uptime-kuma/blob/main/uptime-calculator.js) aggregating statistics for dashboards.
- **Socket.io** broadcasts real-time updates through [`server/socket-handlers/monitor-socket-handler.js`](https://github.com/louislam/uptime-kuma/blob/main/server/socket-handlers/monitor-socket-handler.js), while the notification engine in [`server/notification.js`](https://github.com/louislam/uptime-kuma/blob/main/server/notification.js) dispatches alerts only on status transitions.
- **Maintenance windows** and **Prometheus metrics** extend the core pipeline with operational flexibility and external monitoring integration.

## Frequently Asked Questions

### How does Uptime Kuma schedule monitor checks?

Uptime Kuma uses the **croner** npm package in [`server/jobs.js`](https://github.com/louislam/uptime-kuma/blob/main/server/jobs.js) to schedule checks. For interval-based monitors, it converts the seconds value into a cron pattern; for cron-based monitors, it uses the provided expression directly. Each active monitor receives its own Cron job instance that invokes `monitor.run()` from [`server/model/monitor.js`](https://github.com/louislam/uptime-kuma/blob/main/server/model/monitor.js).

### What happens when a monitor status changes from UP to DOWN?

When [`server/model/monitor.js`](https://github.com/louislam/uptime-kuma/blob/main/server/model/monitor.js) detects a status change during heartbeat generation, it emits a Socket.io event for real-time UI updates via [`server/socket-handlers/monitor-socket-handler.js`](https://github.com/louislam/uptime-kuma/blob/main/server/socket-handlers/monitor-socket-handler.js). Simultaneously, [`server/notification.js`](https://github.com/louislam/uptime-kuma/blob/main/server/notification.js) compares the previous and current heartbeat statuses, then triggers all enabled notification providers with the monitor details and new status.

### Where does Uptime Kuma store monitoring data?

All monitor definitions reside in the `monitor` table, while individual check results are stored in the `heartbeat` table, both managed through SQLite by [`server/model/monitor.js`](https://github.com/louislam/uptime-kuma/blob/main/server/model/monitor.js) and [`server/model/heartbeat.js`](https://github.com/louislam/uptime-kuma/blob/main/server/model/heartbeat.js) respectively. The [`uptime-calculator.js`](https://github.com/louislam/uptime-kuma/blob/main/uptime-calculator.js) module queries these tables to compute uptime percentages and response time averages on demand.

### How can I add a custom monitor type to Uptime Kuma?

Create a new JavaScript file in `server/monitor-types/` that exports a class implementing a `ping` method returning a heartbeat object. The `Monitor.run()` method in [`server/model/monitor.js`](https://github.com/louislam/uptime-kuma/blob/main/server/model/monitor.js) dynamically requires files from this directory based on the monitor's `type` property, making the system extensible without modifying core scheduling logic.