
Single-binary observability, time-series storage, and built-in dashboards for Raspberry Pi, edge devices, appliances, and local metrics.
Ingest metrics, query history, explore series, edit dashboards in the browser,
and inspect data offline with nanocli without assembling a separate TSDB,
dashboard service, or support stack.
Designed for the cases where a bigger observability stack is heavier than the problem: one machine, local files, clear operational behavior, and a UI that is ready as soon as the binary starts.
One binary. Local files. Built-in dashboard and editor. Offline CLI.
nanotdb against a local data directory.drip.nanocli when you want to shape dashboards or inspect data offline.Run drip on a Raspberry Pi or small Linux box to collect host metrics, store
them locally in NanoTDB, inspect them live in the built-in dashboard or
Explore, and use nanocli when you need offline inspection, export, recovery,
or rollup operations.
Actual live Raspberry Pi data:
| Day | Metrics | Points | Metric file size | Coverage |
|---|---|---|---|---|
| 2026-05-22 | 83 | 693,091 | 757 KB | 24h |
| 2026-05-23 | 83 | 717,036 | 935 KB | 24h |
| Question | NanoTDB | Bigger stack |
|---|---|---|
| Single Raspberry Pi or edge box? | One binary, local files, built-in dashboard | Usually multiple services and more moving parts |
| Need local observability first? | Storage, UI, CLI, and rollups are already together | Often starts with separate TSDB + dashboard + supporting services |
| Want to inspect everything on disk? | WAL, manifests, catalog, and data files stay understandable | More layers and components between writes and storage |
| Need huge fleet-scale cardinality? | Not the target | Usually the better fit |
nanocli lets you inspect, export, recover, and compare data without a running server.| Good fit | Use something larger |
|---|---|
| Single-binary observability on one machine | Distributed or horizontally scaled deployments |
| Raspberry Pi, edge nodes, appliances, and local app metrics | Large fleets and high-cardinality multi-tenant workloads |
| Hundreds of metrics you want to keep local and inspect directly | Broader ecosystems where many external integrations matter more than simplicity |
| Built-in dashboard plus offline CLI workflow | Systems that need looser ordering guarantees or broader platform features |
NanoTDB fits best when you want:
NanoTDB is not trying to be:
NanoTDB is a strong fit for small Linux systems where you want to keep metrics
local, survive restart, and avoid wearing out SD storage with unnecessarily
heavy write patterns. Pair it with drip when you want CPU, memory, disk, IO,
network, load, one-wire, or SD write probe metrics on one box, then view them
through the built-in dashboard without standing up a second service.
If you have one appliance, one embedded app, or one self-hosted node, NanoTDB gives you metric writes, queries, rollups, dashboarding, and offline inspection without standing up a larger metrics platform just to answer simple history questions.
If your data is fundamentally numeric time-series data, NanoTDB is often easier
to live with than plain logs. You keep a queryable history, can inspect the WAL
or .dat files directly with nanocli, and can delete old partitions as a
simple retention policy.
When you want recent raw detail plus longer-term summaries, NanoTDB's built-in rollups let you keep local aggregates without building a separate compaction or downsampling pipeline.
Start here:
Terminal 1:
mkdir -p ~/nanotdb-data
./nanotdb --init --config ~/nanotdb-data/engine.toml
./nanotdb --config ~/nanotdb-data/engine.toml
Terminal 2:
curl -X POST "http://localhost:8428/api/v1/import" \
-d $'demo/room.temp 21.5\ndemo/room.humidity 48'
curl "http://localhost:8428/api/v1/query?query=demo/room.temp"
./nanocli inspect wal --root ~/nanotdb-data --db demo --verbose
That flow is the point of NanoTDB: start one binary, write a few metrics, query them back, inspect the local files, and serve a local dashboard without standing up anything else.
For the built-in browser UI and dashboard customization, see docs/DASHBOARD.md.
Prefer ready-to-use binaries? Download the latest release assets from GitHub Releases:
nanotdb-linux-armv6-rpi0-rpi1 and nanocli-linux-armv6-rpi0-rpi1nanotdb-linux-armv7-rpi3-rpi4 and nanocli-linux-armv7-rpi3-rpi4nanotdb-linux-arm64 and nanocli-linux-arm64Release/change history:
For technical deep-dives, continue below.
A database in NanoTDB is an isolated local namespace such as prod, sensors,
or weather.
Each database has its own:
.dat filesThat makes it easy to reason about retention, inspection, backup, and failure isolation one database at a time.
A metric is one numeric time-ordered stream inside a database.
Examples:
room.temproom.humiditycpu.usage_activedisk.sd_write_probe_msEach metric keeps one numeric type for its lifetime: int32 or float32.
NanoTDB writes and reads line protocol in this shape:
DB/metric.name value [timestamp]
Examples:
prod/room.temp 21.5 1715000000000000000
sensors/pressure.hpa 1013
weather/outdoor.humidity 48
DB is the database name.metric.name is the metric identifier.value is an integer or float.timestamp is optional; if omitted, NanoTDB uses the current time.For a deeper storage and query walkthrough, see docs/ARCHITECTURE.md.
WAL means write-ahead log.
In NanoTDB, each database has a local <db>.wal file that protects the newest
samples before they are flushed into durable .dat pages.
That matters for both crashes and normal shutdown:
This is one of NanoTDB's strongest operational properties for edge systems: the latest data is not only local, it is recoverable after restart without needing an external service.
The main WAL and durability knobs are in engine.toml and per-database
manifests:
wal.max_segment_size: how large the WAL is allowed to grow before reset after flush.wal.fsync_policy: segment for better throughput, always for stronger per-append durability.durability.profile: strict, balanced, or throughput for page/catalog fsync behavior.manifest_defaults.wal.enabled: enable or disable WAL for newly created databases.manifest_defaults.wal.skip_before: skip WAL for older backfill samples.manifest_defaults.page.max_records, max_bytes, and max_age: control how quickly in-memory pages roll over and flush, which affects how long data remains WAL-backed before landing in .dat files.If you want the strongest local recovery posture, the conservative end of the range is:
wal.fsync_policy = "always"durability.profile = "strict"If you want less write overhead and can tolerate more crash risk, move toward
segment and balanced or throughput.
NanoTDB's durable .dat files are small, append-only, and friendly to simple
retention and backup workflows.
That matters operationally, especially on SD-backed systems:
As one real Pi test point, a 69-metric workload sampled every 10 seconds
produced about 0.7 MB for a full day in one .dat file, which worked out to
under 2 bytes per metric point on disk after compression. Treat that as a
real-world example, not a universal promise, but it shows why NanoTDB can be a
very SD-friendly fit for local telemetry.
Plain logs are often enough until you want to ask metric-shaped questions like:
You can force numeric history into logs, but querying, retention, aggregation, and inspection stay awkward. NanoTDB keeps the operational simplicity of local files while giving you metric-native writes, queries, rollups, and offline inspection.
Sometimes a larger metrics stack is the right answer. NanoTDB is for the cases where it is not.
Choose NanoTDB when you want:
$ claude mcp add nanotdb \
-- python -m otcore.mcp_server <graph>