Source & license
Upstream license: MIT
License TL;DR
You can use it, change it, self-host it and sell it. Keep the original copyright and license notice with copies of the code. You don’t have to publish your changes. The authors don’t promise it will work.
Explain MIT in plain English →Summary of the main license. Separate packages and assets can have different terms.
Inspect repository ↗Read this project’s actual license ↗Repository owner
See the upstream repository for the original creator and contributors.
Maintain this project? Maintainer verification →Cloudflare hosting
Free tier eligible within limits
A small number of monitors and low public traffic can fit Workers and D1 free allowances. Every-minute checks consume scheduled CPU and D1 writes; the monitor count and retention must be bounded against daily quotas. Optional notification providers are separate.
Hosting requirements
- Start with a small monitor set, measure the scheduler/request CPU and actual rows written rather than assuming one row per check.
- Keep D1 below 5M rows read/day, 100k rows written/day and 5GB total; SQL indexes can increase billed writes.
- Source and configuration review establishes a deployment path and conditional costs; this candidate was not executed or load-tested.
Sources checked 01/10/2026
Repository snapshot: eebc8ac. Hosting eligibility reflects the deployment documentation and listed assumptions.
- uptimerobot ↗
| | | |---|---| | [Cloudflare](docs/cloudflare.md) | deploying the Worker, custom hostname, limits | | [Self-hosting](docs/self-hosting.md) | Docker, compose, from a checkout | | [Kubernetes](deploy/k8s/README.md) | manifests, one replica, seeding in-cluster | | [Monitors](docs/monitors.md) | the rows that say what is watched | | [Configuration](docs/configuration.md) | every variable, on both runtimes | | [API](docs/api.md) | JSON, RSS, badge, notices, machine access | | [Upgrading](docs/UPGRADING.md) | schema additions, moving between runtimes | | [Installing with an agent](docs/agent-install.md) | a runbook: commands, checks, and what each error means |
- better-stack ↗
| | | |---|---| | [Cloudflare](docs/cloudflare.md) | deploying the Worker, custom hostname, limits | | [Self-hosting](docs/self-hosting.md) | Docker, compose, from a checkout | | [Kubernetes](deploy/k8s/README.md) | manifests, one replica, seeding in-cluster | | [Monitors](docs/monitors.md) | the rows that say what is watched | | [Configuration](docs/configuration.md) | every variable, on both runtimes | | [API](docs/api.md) | JSON, RSS, badge, notices, machine access | | [Upgrading](docs/UPGRADING.md) | schema additions, moving between runtimes | | [Installing with an agent](docs/agent-install.md) | a runbook: commands, checks, and what each error means |
- pingdom ↗
| | | |---|---| | [Cloudflare](docs/cloudflare.md) | deploying the Worker, custom hostname, limits | | [Self-hosting](docs/self-hosting.md) | Docker, compose, from a checkout | | [Kubernetes](deploy/k8s/README.md) | manifests, one replica, seeding in-cluster | | [Monitors](docs/monitors.md) | the rows that say what is watched | | [Configuration](docs/configuration.md) | every variable, on both runtimes | | [API](docs/api.md) | JSON, RSS, badge, notices, machine access | | [Upgrading](docs/UPGRADING.md) | schema additions, moving between runtimes | | [Installing with an agent](docs/agent-install.md) | a runbook: commands, checks, and what each error means |
- workers ↗
e rows in D1 (see schema.sql), not config in # a file — a monitor's URL is often somebody's hostname, and this repository # is public. name = "nabiz" main = "src/worker.ts" compatibility_date = "2026-08-01" compatibility_flags = ["nodejs_compat"] [triggers] crons = ["* * * * *"] # Workers Logs, inside the free tier — a cron that fails silently is a # status page lying by omission. [observability] enabled = true [[d1_databases]] binding = "DB" database_name = "nabiz" database_id = "REPLACE_WITH_YO
- d1 ↗
, inside the free tier — a cron that fails silently is a # status page lying by omission. [observability] enabled = true [[d1_databases]] binding = "DB" database_name = "nabiz" database_id = "REPLACE_WITH_YOUR_D1_ID" [vars] # "en", "tr", "de", "es", "fr", "zh-CN" LANG = "en" TITLE = "nabiz" # Optional, as secrets (`wrangler secret put …`): # TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID — a message on every state change # ALERT_WEBHOOK_URL — the same, as JSON to your own endpoin
- free-tier-eligible ↗
# Copy this next to your own deployment notes, fill in the two blanks, and # `wrangler deploy`. Monitors are rows in D1 (see schema.sql), not config in # a file — a monitor's URL is often somebody's hostname, and this repository # is public. name = "nabiz" main = "src/worker.ts" compatibility_date = "2026-08-01" compatibility_flags = ["nodejs_compat"] [triggers] crons = ["* * * * *"] # Workers Logs, inside the free tier — a cron that fails silently is a # status page lying by omission. [observability] enabled = true [[d1_databases]] binding = "DB" database_name = "nabiz" database_id = "REPLACE_WITH_YOUR_D1_ID" [vars] # "en", "tr", "de", "es", "fr", "zh-CN" LANG = "en" TITLE = "nabiz" # Optional, as secrets (`wrangler secret put …`): # TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID — a messag
- free-tier-eligible ↗
| **Free** | 100,000 per day | No charge for duration | 10 milliseconds of CPU time per invocation |
- free-tier-eligible ↗
| Rows read | 5 million / day | First 25 billion / month included + $0.001 / million rows |
- free-tier-eligible ↗
| Rows written | 100,000 / day | First 50 million / month included + $1.00 / million rows |
- MIT ↗
MIT License Copyright (c) 2026 productdevbook Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONN
- architecture ↗
# Copy this next to your own deployment notes, fill in the two blanks, and # `wrangler deploy`. Monitors are rows in D1 (see schema.sql), not config in # a file — a monitor's URL is often somebody's hostname, and this repository # is public. name = "nabiz" main = "src/worker.ts" compatibility_date = "2026-08-01" compatibility_flags = ["nodejs_compat"] [triggers] crons = ["* * * * *"] # Workers Logs, inside the free tier — a cron that fails silently is a # status page lying by omission. [observability] enabled = true [[d1_databases]] binding = "DB" database_name = "nabiz" database_id = "REPLACE_WITH_YOUR_D1_ID" [vars] # "en", "tr", "de", "es", "fr", "zh-CN" LANG = "en" TITLE = "nabiz" # Optional, as secrets (`wrangler secret put …`): # TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID — a messag
- architecture ↗
e rows in D1 (see schema.sql), not config in # a file — a monitor's URL is often somebody's hostname, and this repository # is public. name = "nabiz" main = "src/worker.ts" compatibility_date = "2026-08-01" compatibility_flags = ["nodejs_compat"] [triggers] crons = ["* * * * *"] # Workers Logs, inside the free tier — a cron that fails silently is a # status page lying by omission. [observability] enabled = true [[d1_databases]] binding = "DB" database_name = "nabiz" database_id = "REPLACE_WITH_YO
- architecture ↗
, inside the free tier — a cron that fails silently is a # status page lying by omission. [observability] enabled = true [[d1_databases]] binding = "DB" database_name = "nabiz" database_id = "REPLACE_WITH_YOUR_D1_ID" [vars] # "en", "tr", "de", "es", "fr", "zh-CN" LANG = "en" TITLE = "nabiz" # Optional, as secrets (`wrangler secret put …`): # TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID — a message on every state change # ALERT_WEBHOOK_URL — the same, as JSON to your own endpoin
Upstream screenshot · productdevbook/nabiz repository contributors ↗. Depicts the upstream project. We have not deployed and tested a fresh installation here.
What it can replace
Compare the workflow you need. These mappings describe overlap; full feature parity requires a separate comparison.
HTTP availability/latency checks and a public status page; incident timelines, subscriber email and multi-region probing are explicitly outside the documented core.
See supporting source ↗HTTP availability/latency checks and a public status page; incident timelines, subscriber email and multi-region probing are explicitly outside the documented core.
See supporting source ↗HTTP availability/latency checks and a public status page; incident timelines, subscriber email and multi-region probing are explicitly outside the documented core.
See supporting source ↗How it works
The shape of Nabız on Cloudflare, and how it stacks up against the rented tools it replaces.
Architecture
Diagram of deployment declarations at the reviewed commit. Each app has its own entrypoint; declared resources do not prove runtime calls. Follow file and line sources below.
View upstream source ↗Configuration and workflow sources
Reviewed commit eebc8acce25c. Files were read as data; upstream applications and CI jobs were not executed.
Deployment configuration · 1 files
Cloudflare Workers · compatibility 2026-08-01
nabiz · default
Entrypoint: src/worker.ts
Cron triggers (UTC): * * * * *
DB→ D1
Named environments are separate deployments. Bindings are shown only where declared. Configured routes are URL patterns, not verified application endpoints.
Runtime source · handlers, binding usage and workflow steps
Observed TypeScript/JavaScript declarations from Worker entrypoints and resolved relative imports. Calls and workflow steps may run conditionally; their listed order is not a proven end-to-end request flow. Router declarations may be mounted under a prefix or may not be registered. This shows code wiring, not a successful deployment or runtime test. Dynamic wiring, aliases and generated code may not resolve.
- L18 · fetch handler exported · calls preflight, wantsJson, url.toString, cache.match, handle, includes, res.headers.get, ctx.waitUntil, cache.put, res.clone
- L46 · scheduled handler exported · references DB · calls tick, getUTCMinutes
Environment references: env.DB
- L30 · json calls (conditional paths may differ): JSON.stringify
- L41 · statusJson calls (conditional paths may differ): rows, overall, json, toISOString, list.map, uptimeOf, REASONS.has, map, eventsView, res.headers.set
- L81 · historyJson calls (conditional paths may differ): rows, json, list.map, r.days.map, Math.round
- L107 · badge calls (conditional paths may differ): overall, rows
- L132 · escXml calls (conditional paths may differ): ch.codePointAt
- L145 · plain calls (conditional paths may differ): trim, replace, body.split
- L161 · feed calls (conditional paths may differ): escXml, eventsView, t, entries.push, toUTCString, sevLabel, slice, plain, render, join, map, entries.toSorted
- L302 · refused calls (conditional paths may differ): json, answer.headers.set
- L311 · jsonBody calls (conditional paths may differ): request.json
- L332 · forgive calls (conditional paths may differ): attempts.delete, request.headers.get
- L341 · throttled calls (conditional paths may differ): Date.now, attempts.delete, slice, toSorted, attempts.entries, request.headers.get, attempts.get, attempts.set
- L367 · authorized calls (conditional paths may differ): request.headers.get, enc.encode, subtle.timingSafeEqual
- L384 · postNotice calls (conditional paths may differ): jsonBody, json, body.body.trim, isLang, SEVERITIES.has, addNotice
- L411 · postResolve calls (conditional paths may differ): jsonBody, json, Number.isSafeInteger, resolveNotice
- L421 · noticesJson calls (conditional paths may differ): json, list.map, toISOString, render
- L24 · tick calls (conditional paths may differ): monitors, AbortSignal.timeout, Promise.all, watched.map, probe, record, Math.round, alert, langOf, Math.max, console.error, join, changes.map, prune
Environment references: env.LANG
- L5 · esc calls (conditional paths may differ): replace, s.replace
- L18 · stars calls (conditional paths may differ): replace, s.replace
- L26 · inline calls (conditional paths may differ): held.push, text.replace, Number, replace, s.replace, hold, put, stars
- L57 · render calls (conditional paths may differ): split, esc, md.trim, join, blocks.map, block.split, lines.every, startsWith, l.trimStart, lines.map, inline, slice
- L12 · esc calls (conditional paths may differ): s.replace
- L23 · percent calls (conditional paths may differ): toFixed, Math.floor, plain.replace
- L39 · when calls (conditional paths may differ): slice, replace, toISOString
- L46 · bars calls (conditional paths may differ): days.map, slice, toISOString, Date.now, byDay.get, cells.push, esc, t, percent, cells.join
- L63 · uptimeLabel calls (conditional paths may differ): uptimeOf, percent
- L71 · path calls (conditional paths may differ): join, xy.map, x.toFixed, y.toFixed
- L79 · sparkline calls (conditional paths may differ): points.filter, Math.max, Math.min, points.forEach, runs.push, run.push, at, join, runs.map, map, runs.filter, path, ex.toFixed, sx.toFixed, t, ey.toFixed
- L119 · sevLabel calls (conditional paths may differ): t
- L132 · callout calls (conditional paths may differ): esc, sevLabel, when, render
- L140 · pastNotice calls (conditional paths may differ): t, when, render
- L148 · serviceRow calls (conditional paths may differ): t, sparkline, uptimeLabel, esc, bars, replace, String
- L189 · eventLine calls (conditional paths may differ): esc, t, when
- L45 · groupOf calls (conditional paths may differ): trim
- L62 · medianDays calls (conditional paths may differ): byDay.get, seen.push, byDay.set, members.toSorted, out.push, out.toSorted
- L110 · rows calls (conditional paths may differ): shaped.get, shape, shaped.set
- L118 · shape calls (conditional paths may differ): data.monitors.forEach, groupOf, grouped.get, held.members.push, grouped.set, data.states.get, out.push, data.days.get, data.latency.get, data.spark.get, members.filter, isDown, medianDays, members.map, map, out.toSorted
- L179 · overall calls (conditional paths may differ): list.filter, known.filter, known.some
- L217 · eventsView calls (conditional paths may differ): monitors.map, groupOf, groups.get, states.get, held.down.add, groups.set, byId.get, out.push, Boolean, isDown, group.down.add, group.down.delete
- L19 · monitors calls (conditional paths may differ): all, db.prepare
- L26 · utcDay calls (conditional paths may differ): slice, toISOString
- L33 · record calls (conditional paths may differ): Date.now, utcDay, writes.push, bind, db.prepare, db.batch, all, states.map, stateWrites.push, known.get, put, changes.push, event, Math.max, Math.round, Boolean, forget
- L180 · prune calls (conditional paths may differ): Date.now, db.prepare, map, watched.filter, Boolean, out.push, join, ids.slice, db.batch, bind, before, slice, toISOString, orphans, reconcile, forget
- L238 · recentEvents calls (conditional paths may differ): all, bind, db.prepare
- L309 · holdFor calls (conditional paths may differ): Math.max
- L314 · forget calls (conditional paths may differ): recent.delete
- L319 · forPage calls (conditional paths may differ): recent.get, Date.now, read, recent.set
- L332 · asDay calls (conditional paths may differ): slice, toISOString
- L336 · read calls (conditional paths may differ): monitors, Date.now, asDay, db.batch, db.prepare, bind, states.set, Boolean, days.get, list.push, days.set, latency.set, Math.floor, spark.get, Array.from, spark.set
- L432 · notices calls (conditional paths may differ): all, bind, db.prepare
- L453 · addNotice calls (conditional paths may differ): first, bind, db.prepare, Date.now, forget
- L469 · resolveNotice calls (conditional paths may differ): run, bind, db.prepare, Date.now, forget
- L11 · held calls (conditional paths may differ): Math.floor, t, say, replace
- L42 · oneLine calls (conditional paths may differ): ch.codePointAt
- L59 · to calls (conditional paths may differ): sending, console.error
- L78 · alert calls (conditional paths may differ): changes.map, oneLine, t, held, lines.join, toISOString, sends.push, to, fetch, JSON.stringify, AbortSignal.timeout, Promise.all, answers.filter
Environment references: env.TELEGRAM_BOT_TOKEN · env.TELEGRAM_CHAT_ID · env.ALERT_WEBHOOK_URL
- L35 · within calls (conditional paths may differ): AbortSignal.timeout, any
- L51 · firstOf calls (conditional paths may differ): chunk.subarray, controller.enqueue, controller.terminate, text, body.pipeThrough
- L73 · probe calls (conditional paths may differ): Date.now, within, fetch, firstOf, body.includes
Build and deployment pipeline · 2 GitHub Actions workflows
Repository CI declarations, separate from runtime request processing. Job dependencies and conditions are shown as written; long commands are shortened with an ellipsis; a workflow file does not prove a recent successful run.
Triggers: push, pull_request
check · no job dependencies declared
- actions/checkout@v5
actions/checkout@v5 - oven-sh/setup-bun@v2
oven-sh/setup-bun@v2 - Shell command
bun install --frozen-lockfile - Shell command
bun run typecheck - Shell command
bunx oxlint --deny-warnings - Shell command
bunx oxfmt --check src test - Shell command
bun test - Shell command
bun run build - Shell command
bunx wrangler deploy -c dist/server/wrangler.json --dry-run - Shell command
bun run build:server
image · no job dependencies declared
- actions/checkout@v5
actions/checkout@v5 - Shell command
docker build -t nabiz:ci . - it answers on the port it says
docker run -d --name nabiz-ci -p 8080:8080 nabiz:ci for i in $(seq 1 30); do code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/health || true) [ "$code" = "204" ] && break sleep 1 done test "$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/)" = "200" test "$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/health)" = "204" docker logs nabiz-ci - Shell command
kubectl kustomize deploy/k8s > /dev/null
Triggers: push, workflow_dispatch
image · no job dependencies declared
- actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09
actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 - oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76
oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 - the tag, the package and the header agree
tag="${GITHUB_REF_NAME#v}" pkg=$(node -p "require('./package.json').version") src=$(grep -oP 'VERSION = "\K[^"]+' src/lib/version.ts) echo "tag=$tag package.json=$pkg src=$src" test "$tag" = "$pkg" test "$tag" = "$src"Condition: github.ref_type == 'tag' - Shell command
bun install --frozen-lockfile - Shell command
bun run check - docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130
docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 - docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f - docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 - Shell command
top=$(git tag --list 'v*' --sort=-v:refname | head -1) echo "newest=$([ "$top" = "$GITHUB_REF_NAME" ] && echo yes || echo no)" >> "$GITHUB_OUTPUT" echo "this=$GITHUB_REF_NAME newest=$top"Condition: github.ref_type == 'tag' - docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051
docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 - docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 - it answers on the port it says
docker run -d --name nabiz-smoke -p 8080:8080 nabiz:smoke for i in $(seq 1 30); do code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/health || true) [ "$code" = "204" ] && break sleep 1 done test "$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/)" = "200" test "$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/health)" = "204" # The build says which build it is, and it is this one: the gate # above reads the checkout, this reads what was actually bu… - docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
build: astro buildbuild:server: NABIZ_TARGET=node astro builddeploy: astro build && wrangler deploy -c dist/server/wrangler.json
Repository README
View original on GitHub ↗Full upstream document by @productdevbook · README.md · snapshot eebc8ac
nabiz
A status page that keeps beating when your server does not —
one Cloudflare Worker, or one container on a machine you own.
What it is
Astro renders the page, a probe checks every monitor once a minute, and
the history lives in a database next to it. On Cloudflare that is one
Worker with a cron trigger and D1, inside the free tier. On your own
hardware it is one container with an interval and a SQLite file — same
source, same schema. nabız is Turkish for "pulse"; the ASCII spelling
nabiz is used throughout.
Documentation
| Cloudflare | deploying the Worker, custom hostname, limits |
| Self-hosting | Docker, compose, from a checkout |
| Kubernetes | manifests, one replica, seeding in-cluster |
| Monitors | the rows that say what is watched |
| Configuration | every variable, on both runtimes |
| API | JSON, RSS, badge, notices, machine access |
| Upgrading | schema additions, moving between runtimes |
| Installing with an agent | a runbook: commands, checks, and what each error means |
Features
- One probe per monitor per minute: method, expected status, timeout, optional body match.
- Anti-flap: a watched monitor is called down after
fail_thresholdconsecutive failures (default 2); recovery is immediate, and a monitor that is already down when first seen is believed at once. - 90-day uptime bars, and a latency sparkline once there are probes in two different hours — it averages by the hour, so a fresh deployment has no waveform until the clock crosses one.
- Grouped monitors: one row saying how the group is, never how many it speaks for and never their names.
- Operator notices in markdown, with severity and per-language targeting.
- Alerts to Telegram and a webhook on state changes.
- Six languages (en, tr, de, es, fr, zh-CN), light and dark, auto-refresh.
- JSON API, RSS feed, SVG badge,
llms.txt.
Not included: incident timelines, subscriber emails, multi-region probes.
Quick start
On your own machine
docker run -d --name nabiz -p 8080:8080 -v nabiz:/data \
-e NABIZ_TITLE="status" -e ADMIN_TOKEN="$(openssl rand -hex 32)" \
ghcr.io/productdevbook/nabiz:latest
On Cloudflare
git clone https://github.com/productdevbook/nabiz && cd nabiz && bun install
bunx wrangler d1 create nabiz # id goes into wrangler.toml
bunx wrangler d1 execute nabiz --remote --file schema.sql
bun run deploy
Either way the page comes up empty and working — a heading with nothing
under it is the correct first sight. Monitors are rows you add next, and
the first bar appears within one probe interval: see
Monitors. Keep the token you generated above; it is what lets you write notices.
Nothing on the page prints it again — docker inspect nabiz will, which
is also a reason not to leave it on a machine other people can reach.
Development
bun install
bunx wrangler d1 execute nabiz --local --file schema.sql # once
bun run dev # :4321, local D1
bun run check # what CI runs
Everything under src/lib/ is plain TypeScript against a narrow database
interface (src/lib/db.ts) that D1 already satisfies and SQLite is made to
(src/lib/sqlite.ts). That seam is the whole difference between the two
runtimes: the page, the probes and the state machine are one copy.
License
MIT. Icons from Lucide (ISC).
Frequently asked about Nabız
What is Nabız?+
Nabız is a self-hosted Better Stack/Pingdom alternative built on the Cloudflare developer platform. HTTP uptime checks and a public status page from one Worker
What does Nabız replace?+
Nabız is listed as an alternative to Better Stack, Pingdom, UptimeRobot. Compare the features and tradeoffs before migrating.
What Cloudflare primitives does Nabız use?+
Nabız is built on D1, Workers.
How much does Nabız cost to run?+
A small number of monitors and low public traffic can fit Workers and D1 free allowances. Every-minute checks consume scheduled CPU and D1 writes; the monitor count and retention must be bounded against daily quotas. Optional notification providers are separate. Start with a small monitor set, measure the scheduler/request CPU and actual rows written rather than assuming one row per check. Keep D1 below 5M rows read/day, 100k rows written/day and 5GB total; SQL indexes can increase billed writes. Source and configuration review establishes a deployment path and conditional costs; this candidate was not executed or load-tested. Check current Cloudflare pricing before deploying.
Is Nabız open source?+
The upstream repository declares the MIT license. Read its terms at https://raw.githubusercontent.com/productdevbook/nabiz/eebc8acce25c5db5001398b483ba7a8016c3c5aa/LICENSE. Source code and contributor credit are available at https://github.com/productdevbook/nabiz.




Discussion · 0
sign in to comment →