---
title: "How Meshtastic Metrics Exporter Turned Eight Prometheus Queries Into One with Tiger Data"
published: 2026-09-16T08:44:25.000-04:00
updated: 2026-09-16T08:44:25.000-04:00
excerpt: "Meshtastic Metrics Exporter reduced 500K+ Prometheus metric series to one Postgres database: consolidated eight queries into one with Tiger Data for 10,000 mesh radio nodes."
tags: Dev Q&A, TimescaleDB
authors: Andrew Stebbins
---

> **TimescaleDB is now Tiger Data.**

_An open source monitoring tool for the Meshtastic mesh radio community moved off Prometheus, where 10,000 nodes meant half a million metric series, and put node data and telemetry history on a single Postgres database with TimescaleDB._

_This is an installment of our “Community Member Spotlight” series, in which we invite our customers to share their work, spotlight their success, and inspire others with new ways to use technology to solve problems._

_Meshtastic Metrics Exporter is an open source monitoring tool built by Gleb Tcivie, a software engineer and member of the Meshtastic community, that decodes mesh network traffic into a TimescaleDB database and ships ready-made Grafana dashboards. After outgrowing Prometheus at a few thousand nodes, the project moved its metrics and node data onto a single Postgres database running TimescaleDB, and it now ships as three containers a mesh operator can start with one command._

## About the project

Meshtastic firmware turns cheap LoRa radios into an off-grid mesh network, and that network throws off a constant stream of diagnostic data: device telemetry, position, power, packet counts, radio metadata. The people running these networks are mesh operators, not database administrators, and most monitoring stacks assume the opposite: labeled metrics, a scrape budget, and someone on staff who knows how to keep the metrics store from falling over as node count grows.

For the Meshtastic community, that mismatch showed up as the network grew. People needed to find a malfunctioning node quickly, and they did not want to learn a query language built for someone else's operations team.

Meshtastic Metrics Exporter closes that gap. A Python service listens to the mesh MQTT feed, decodes the protobufs, and writes everything into a Postgres database running TimescaleDB. Grafana dashboards ship pre-provisioned, so clicking any node id opens a page built from that node's full history. The whole thing starts with one docker compose up -d, because the person running it is a mesh operator, not a database person.

The project started inside the Meshtastic community and has since spread to the global Meshtastic Discord, where other community-run networks have picked it up.

Gleb Tcivie built and maintains the project alone, alongside his work as a software engineer.

## The challenge

Before TimescaleDB, Meshtastic Metrics Exporter ran on Prometheus. Prometheus worked fine at low scale, and stopped working as the network grew.

The problem was cardinality. Node information, name, hardware model, role, has to live in metric labels, and every distinct combination of labels creates a new series. When Gleb tested the exporter against the public Meshtastic MQTT server, around 10,000 nodes showed up in 20 minutes. With roughly 55 metrics per node, that works out to close to half a million series. Prometheus gives a scrape job 10 seconds to finish, and this was well past that budget.

Node metadata, meanwhile, lived in a separate Postgres database, so the project was maintaining two databases with no way to talk to each other. Correlating a node's identity with its history meant querying both and joining the results by hand.

## Why TimescaleDB

The project already used Postgres to store node metadata, so when Gleb found that TimescaleDB is an extension on top of Postgres rather than a separate system, the decision looked different from a typical database migration. Adopting it meant removing a database, not adding one.

He looked at VictoriaMetrics and InfluxDB first. Both would have solved the metrics side of the problem, but neither would have touched the other half: node metadata would still live somewhere else, split from the history it describes.

With TimescaleDB, Gleb could write ordinary SQL, join node details directly against their time-series history, and declare retention and compression once instead of writing and maintaining cleanup jobs.

> The ability to quickly insert data and not worry about size or partitioning, and the ability to easily query with natural SQL language, made it a really good choice that fit this project like a glove. \- Gleb Tcivie, Creator, Meshtastic Metrics Exporter

## The Meshtastic Metrics Exporter stack

Meshtastic radios publish to an MQTT broker over the mesh. A Python exporter service subscribes to that feed, decodes the Meshtastic protobufs, validates each device, and writes the resulting time-series measurements straight into a Postgres database running TimescaleDB, on Postgres 16. Grafana reads from that same database using dashboards that ship already built, so any node id can be clicked into a page that pulls together eight tables of history: device telemetry, environment readings, air quality, power, PAX counts, position, packet counters, and radio metadata.

The whole system runs as three containers defined in a single docker-compose.yml. That's deliberate. A new mesh community can go from cloning the repo to working dashboards in the time it takes to run one command.

![Meshtastic radios feed an MQTT broker. A Python exporter decodes and writes to Tiger Data. Grafana reads the same database for dashboards.](https://assets.tigerdata.com/blog/2026/09/meshtastic.svg)

__Meshtastic radios feed an MQTT broker. A Python exporter decodes and writes to Tiger Data. Grafana reads the same database for dashboards.__

## Building a _complete_ node profile from incomplete data

The exporter never gets one complete record for a node. Packet types arrive on wildly different schedules, so a node's profile in node\_details is built up gradually, column by column, as different packets get decoded.

A node's row starts out almost empty: the moment any packet from a node\_id is seen, a row is created with just that ID, and every other field null. A NODEINFO packet, which shows up roughly once an hour, fills in the short name, long name, hardware model, and role. A MapReport fills in firmware version, region, modem preset, and position. Telemetry, battery level, temperature, humidity, keeps landing in TimescaleDB hypertables every couple of minutes the entire time, independent of what node\_details knows so far.

A separate table, node\_configurations, tracks how often each node actually reports each kind of data. Nobody configures these intervals. A TimescaleDB scheduled job recomputes them every ten minutes from the real gaps between packets already stored.

> Nobody tells us those rates, we derive them, and none of it requires connecting every node to our MQTT server.  - Gleb Tcivie, Creator, Meshtastic Metrics Exporter

Those inferred intervals matter beyond bookkeeping. Mesh capacity is limited, and a single misconfigured node, one broadcasting metadata far more often than it needs to, or relaying packets too many hops past where they're useful, can eat a real share of it. Interval history is what makes a noisy node visible enough to find and fix.

None of this requires talking to every node directly, either. Monitoring nodes are typically stationary, internet-connected devices placed to catch as much mesh traffic as possible, and because Meshtastic nodes rebroadcast what they hear, one monitoring node picks up activity from other nodes many hops away that it never talks to directly.

![How a single node_details row fills in as different packet types arrive.](https://assets.tigerdata.com/blog/2026/08/Meshtastic-Metrics-Exporter-Gleb-Table-Graphic.png)

__How a single node\_details row fills in as different packet types arrive.__

## Results

### One query instead of eight

The clearest result is the node drill-down page. Click a node id anywhere in the dashboards, and the page joins that node's details against eight tables of history in a single database. That correlation, tying a node's hardware and role to its telemetry, position, and power history in one place, was not something the old stack could do at all.

> With Prometheus this was 8 separate queries that you can’t really correlate.  - Gleb Tcivie, Creator, Meshtastic Metrics Exporter

### Growth costs disk space, not scrape time

The scraping problem that drove the original cardinality math is gone, because there is no scrape step anymore. The exporter writes straight into the database as data arrives. A larger mesh now costs Gleb disk space instead of scrape budget. Storage management is similarly hands off: data is chunked by day, compressed after 14 days, and dropped after 30, rules Gleb set once rather than cleanup code he has to maintain.

## Looking ahead

Gleb has not committed to a specific next feature. What he has is a project that has already outgrown its original community and spread to the wider Meshtastic Discord, with other community-run networks adopting it. As more of those networks come online, the architecture decision he made early, one Postgres database instead of a metrics store split from a metadata store, means growth adds nodes and history to the same tables rather than a second system to reconcile.

> I really enjoyed working with TimescaleDB. It’s a good tool, and it’s definitely something I’ll keep reaching for whenever I have time series data.  - Gleb Tcivie, Creator, Meshtastic Metrics Exporter