Skip to content
Explainer · Time-series databases

VictoriaMetrics Explained: Storage, Metrics and Retention

VictoriaMetrics is an open source time-series database and monitoring stack that is compatible with Prometheus. It stores metrics as series identified by a name and labels, accepts data in many formats including Prometheus remote write and InfluxDB line protocol, and is queried with MetricsQL, a superset of PromQL. This article explains its data model, the single-node and cluster versions, how data is laid out on disk, how retention and deduplication work, how sensor data from buildings fits the model, what Enterprise adds, and when a SQL database is the better choice.

Facts checked 27 October 2026 against the vendors' official documentation. Versions covered: VictoriaMetrics v1.155.0 (released 26 October 2026), documentation at docs.victoriametrics.com as published on 27 October 2026. Next review due April 2027. Products, licences and prices in this field change quickly; confirm on the vendor's site before you choose. No benchmarks are quoted unless the source and test setup are named.
Short answer
  • VictoriaMetrics is Apache License 2.0 software; both the single-node and the cluster versions are open source, and an Enterprise edition adds features such as downsampling and multiple retentions.
  • Its data model is Prometheus-style: a metric name plus labels identifies a series, and each sample is a timestamp and a float value. There is no schema to declare and no SQL.
  • The single-node version is recommended below about a million data points per second; the cluster splits work into vminsert, vmselect and vmstorage, with shared-nothing storage nodes.
  • Data sits in per-month partitions of compressed parts that are merged in the background; -retentionPeriod (default 31 days) removes old data, and -dedup.minScrapeInterval keeps one sample per interval.
  • Our editorial view: it suits metrics and numeric sensor readings queried with PromQL or MetricsQL and Grafana, and is a poor fit for text values, per-event records or relational data such as work orders, because each sample is a float value.
How we know: Research-based from the VictoriaMetrics documentation (single-node, cluster, key concepts, MetricsQL, InfluxDB integration, vmagent, Enterprise and changelog pages), the VictoriaMetrics Enterprise product page and the VictoriaMetrics GitHub repository (README and LICENSE), checked 27 October 2026. The PostgreSQL query that illustrates the documented deduplication rule was run on PostgreSQL 18.6 (PGlite 0.5.11). VictoriaMetrics command-line flags, line-protocol mapping and MetricsQL are adapted from the documentation, were not run here and are labelled as illustrative. Licence terms are quoted from the LICENSE file and the Enterprise documentation; they are a summary, not legal advice. The building example (counts, intervals, retention periods, alert threshold) uses illustrative assumptions, and the absence of MQTT refers only to the README list we checked. Vendor benchmark comparisons in the documentation are deliberately not repeated, and no prices are quoted because none are published.

What VictoriaMetrics is, and who this article is for

VictoriaMetrics is a time-series database written in Go, built for metrics: numeric values sampled over time and identified by labels. It is used as long-term storage for Prometheus, as a drop-in Prometheus data source for Grafana, and as a standalone metrics database. The project also ships agents and tools around it: vmagent for collection, vmalert for alerting rules, vmauth as an authenticating proxy and vmbackup and vmrestore for backups.

This article is for operations and data engineers who already run, or are considering, Prometheus-style monitoring and want to know whether the same store can hold building or plant telemetry. On 27 October 2026 the latest release in the changelog was v1.155.0, released on 26 October 2026. General background is in the time-series database overview, and the monitoring tool trade-offs are covered in Prometheus vs Datadog.

Data model: metric names, labels and samples

A series is a metric name plus a set of label-value pairs, for example ahu_supply_air_temp_c{building="hq",ahu="ahu-01"}. Each raw sample is a millisecond timestamp and a floating-point value. The model is schemaless: new metrics and labels can appear at any time without a CREATE statement. Label values are strings, and the metric name is itself stored as a label called __name__.

Three consequences matter for sensor data:

  • Values are numbers. Data arriving as InfluxDB line protocol is mapped so that each field becomes its own series named {measurement}_{field}, tags become labels, and non-numeric field values are converted to 0. A text status such as "fault" has to be encoded as a number before it is written.
  • Series count drives cost. Every distinct combination of labels is a new series, and the documentation ties resource usage to the number of active series and the churn rate. Keep labels such as building, asset and point type; do not put work-order numbers, user IDs or free text in labels.
  • No joins to business tables. Labels are the only metadata. Asset hierarchies, maintenance contracts and work orders live elsewhere and are joined in reporting tools or a warehouse.
Illustrative data, not run here: an InfluxDB line written to VictoriaMetrics and the series it becomes, adapted from the mapping in the VictoriaMetrics documentation; check it against the documentation for your version before use
# written to http://<victoriametrics-addr>:8428/influx/write
zone,building=hq,zone=l3-01 co2_ppm=612,temp_c=22.4

# stored as two series
zone_co2_ppm{building="hq",zone="l3-01"} 612
zone_temp_c{building="hq",zone="l3-01"} 22.4

Single-node and cluster versions

Single-node. One binary does ingestion, storage and queries, configured with command-line flags. The cluster documentation itself recommends the single-node version for ingestion rates below a million data points per second, because it scales with CPU, RAM and disk and is simpler to run. High availability for single-node is built by running two or more copies fed by vmagent and putting vmauth in front for reads.

Cluster. Three services scale independently:

  • vminsert accepts writes and spreads them across storage nodes by consistent hashing over the metric name and labels;
  • vmstorage stores raw data and answers queries for a time range and label filters; storage nodes do not communicate or share data (a shared-nothing design);
  • vmselect runs queries by fetching data from all storage nodes and merging it.

The cluster version supports multi-tenancy (separate namespaces by account and project ID), which a service provider or a multi-client CAFM platform can use to isolate customers. If a storage node is down, vmselect can return partial results marked "isPartial": true; replication is configured with -replicationFactor.

Storage layout: partitions, parts and indexDB

Incoming samples are buffered in memory and flushed to disk as immutable parts under a month directory such as data/small/2026_10. Inside a part, data is grouped into blocks of up to 8K samples of one series, sorted by timestamp, with timestamps and values compressed into separate files. A part becomes visible only after it is fully written and registered, so a power cut does not leave half-written parts.

Background merges combine small parts into larger ones, which improves compression and reduces the number of files. Merges run per monthly partition, and a partition that stops receiving data eventually stops being merged. Deleting series through the API marks them deleted, but the space is reclaimed only when a merge rewrites the part, which may never happen for old months unless a forced merge is run.

To find series by label, each partition keeps its own inverted index (indexDB) with a global index and a per-day index. This is why the number of new series per day (churn) affects index size: long-lived sensor series with stable labels are cheap, while labels that change constantly are not.

Retention, deduplication and downsampling

  • Retention. -retentionPeriod sets one retention for the whole instance; data older than this is deleted automatically. The default is one month (31 days) and the minimum is 24h or 1d. Values take a unit suffix: the documentation's own sizing example uses -retentionPeriod=100d for a 100-day retention. The documentation says the index for a partition is cleaned up once the partition falls outside the retention period, which indicates that old data is removed partition by partition.
  • Different retentions. Open source has a single retention per instance, so a common pattern is separate instances (for example 31 days for raw readings and several years for roll-ups) with vmauth routing requests. Per-label retention filters are an Enterprise feature.
  • Deduplication. With -dedup.minScrapeInterval set, VictoriaMetrics keeps one raw sample per series per interval: the one with the latest timestamp, and if timestamps tie, the larger value. Set it to the collection interval when two collectors write the same data for high availability.
  • Downsampling. Reducing resolution of old data automatically (for example 1-minute data older than 30 days to 5-minute) is an Enterprise feature. With open source, use recording rules in vmalert to write lower-resolution series into a long-retention instance.
Illustrative configuration, not run here: single-node flags for 400-day retention and 30-second deduplication, adapted from the VictoriaMetrics documentation (400d and 30s are illustrative values; set them from your reporting needs and collection interval); check every setting against the documentation for your version before use
victoria-metrics-prod \
  -storageDataPath=/var/lib/victoria-metrics \
  -retentionPeriod=400d \
  -dedup.minScrapeInterval=30s

The deduplication rule, illustrated in SQL

To make the documented rule concrete, this PostgreSQL query keeps one sample per series per 60-second interval, choosing the latest timestamp and then the larger value, as two high-availability collectors might produce. It ran on PostgreSQL 18.6. It illustrates the rule only; VictoriaMetrics applies it internally during merges and queries, and its interval alignment is its own.

One sample per series per 60 seconds (run on PostgreSQL 18.6)
CREATE TABLE samples (
    series text        NOT NULL,
    ts     timestamptz NOT NULL,
    value  double precision NOT NULL
);

-- Two HA collectors send the same meter, a few seconds apart
INSERT INTO samples VALUES
    ('meter_kwh{building="hq",meter="m-01"}', '2026-10-27 10:00:05+00', 50210.4),
    ('meter_kwh{building="hq",meter="m-01"}', '2026-10-27 10:00:07+00', 50210.4),
    ('meter_kwh{building="hq",meter="m-01"}', '2026-10-27 10:01:05+00', 50211.9),
    ('meter_kwh{building="hq",meter="m-01"}', '2026-10-27 10:01:06+00', 50211.9),
    ('meter_kwh{building="hq",meter="m-01"}', '2026-10-27 10:02:04+00', 50213.1),
    ('meter_kwh{building="hq",meter="m-01"}', '2026-10-27 10:02:04+00', 50213.3);

-- Keep one sample per series per 60-second interval: the latest timestamp, then the larger value
SELECT DISTINCT ON (series, floor(extract(epoch FROM ts) / 60))
       series, ts, value
FROM samples
ORDER BY series, floor(extract(epoch FROM ts) / 60), ts DESC, value DESC;
Result on PostgreSQL 18.6 (PGlite)
                series                 |           ts           |  value
---------------------------------------+------------------------+---------
 meter_kwh{building="hq",meter="m-01"} | 2026-10-27 10:00:07+00 | 50210.4
 meter_kwh{building="hq",meter="m-01"} | 2026-10-27 10:01:06+00 | 50211.9
 meter_kwh{building="hq",meter="m-01"} | 2026-10-27 10:02:04+00 | 50213.3

MetricsQL and getting data in

MetricsQL is VictoriaMetrics' query language. It is backwards-compatible with PromQL, so Grafana dashboards built for Prometheus keep working, and adds functions and some intentional differences. Queries are expressions over series selected by labels, evaluated over a time range and step, rather than SQL statements over tables.

Ingestion formats include Prometheus scraping and remote write, InfluxDB line protocol over HTTP, TCP and UDP, Graphite, OpenTSDB, OpenTelemetry, DataDog agents, JSON lines, CSV and a native binary format. For sites with unreliable links, vmagent buffers data on local disk when the remote store is unavailable and sends it once the connection returns; the documentation names IoT and industrial networks as a use case.

The README we checked lists Prometheus, InfluxDB line protocol, Graphite, OpenTSDB, JSON line, CSV, native, DataDog, NewRelic and OpenTelemetry formats among its ingestion protocols and does not list MQTT, so in a building pipeline a collector such as Telegraf reads the MQTT broker or the BMS and sends line protocol or remote write to vmagent. The broker (MQTT or Kafka) moves messages, VictoriaMetrics stores and serves numeric series for dashboards and alerts, and a warehouse or lakehouse takes long-range analysis that needs joins with asset and CMMS data.

Illustrative queries, not run here: MetricsQL for 15-minute average supply-air temperature and hourly energy per meter, adapted from the MetricsQL documentation; check them against the documentation for your version before use
avg_over_time(ahu_supply_air_temp_c{building="hq"}[15m])

increase(meter_energy_kwh_total{building="hq"}[1h])

Example: building telemetry next to IT monitoring

An estates team already runs Grafana and VictoriaMetrics for server monitoring and wants BMS trends for 25 buildings: AHU supply-air temperature, chiller kW, zone CO2 and meter readings every 30 to 60 seconds, about 50,000 points in total. The building and point counts, intervals, retention periods and the alert threshold below are illustrative assumptions for the example; derive yours from your point list, reporting and compliance needs, and the comfort or safety limits your organisation uses.

  • Telegraf at each site reads the BMS gateway or MQTT broker and writes to a local vmagent, which buffers during WAN outages.
  • Series follow one naming pattern (zone_co2_ppm, chiller_power_kw, meter_energy_kwh_total) with labels building, floor, asset only, which keeps the series count near the point count.
  • A single-node instance with -retentionPeriod=400d holds raw data; vmalert recording rules write 15-minute roll-ups to a second instance kept for five years.
  • Alerts such as "zone CO2 above 1,200 ppm for 20 minutes" run in vmalert and raise a ticket through an integration; the work order itself lives in the CMMS.

About 50,000 series sampled every 30 to 60 seconds is roughly 830 to 1,700 samples per second, far below the million data points per second under which the documentation recommends the single-node version. Size disks by running a day of real traffic and extrapolating, as the documentation recommends: if the data directory grows by a given amount in a day, multiply by the retention in days and add headroom for merges.

Enterprise, security and operations

Open source and Enterprise. Both single-node and cluster versions are open source under the Apache License 2.0; the README says "Yes, we open-source both the single-node VictoriaMetrics and the cluster version", and the text is in the repository as LICENSE. Section 2 of that licence grants "a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work", subject to its conditions. Enterprise adds, among other things, downsampling, multiple retentions per label filter, anomaly detection, backup automation, mTLS between cluster components and long-term support releases. Enterprise binaries are public and need a licence key. The Enterprise documentation says "The use of Enterprise components is permitted in the following cases:" and lists "Evaluation use in non-production setups" with a trial licence and "Production use if you have a valid enterprise contract or valid permit from VictoriaMetrics company." The site footer links an Enterprise Solution Agreement. The vendor page asks you to contact sales for pricing, so we do not quote prices.

Not legal advice. This paragraph quotes the licence and VictoriaMetrics' documentation; read the licence, and the Enterprise agreement if you use Enterprise components, and take advice for your situation.

  • Network exposure. The documentation says all components must run in protected private networks, and requests from untrusted networks must go through an authenticating proxy such as vmauth with TLS termination.
  • Admin endpoints. Protect deletion, snapshot and force-merge endpoints with their auth-key flags.
  • Backups. Use instant snapshots with vmbackup and vmrestore; do not copy snapshot folders with ordinary file tools.
  • Upgrades. Releases are frequent; read the changelog and prefer LTS lines where change control is strict.

When not to use VictoriaMetrics

  • You need SQL. There is no SQL interface. Our editorial view: analysts who expect joins, window functions and ad hoc SQL are usually better served by TimescaleDB or QuestDB.
  • Non-numeric or event data. Text states, alarm messages and per-event records with many attributes do not fit a float-per-sample model; non-numeric InfluxDB fields become 0.
  • Device-centred industrial models. If you want devices, attributes and tables per equipment type, Apache IoTDB or TDengine model that directly.
  • Exact audit history. Deduplication and downsampling deliberately discard samples; our editorial view is that regulatory meter data that must be kept exactly as received belongs in a store without those rules enabled, or in a relational table.
  • Relational records. Work orders and asset registers stay in the CMMS or CAFM database.

See the guide to choosing a time-series database for a wider comparison.

Frequently asked questions

Is VictoriaMetrics open source?

Yes. Both the single-node and cluster versions are under the Apache License 2.0. An Enterprise edition with extra features such as downsampling and per-label retention is sold separately; its documentation permits evaluation in non-production setups with a trial licence and production use with an enterprise contract or permit. This is a summary, not legal advice.

Does VictoriaMetrics support SQL?

No. It is queried with MetricsQL, which is backwards-compatible with PromQL, and works as a Prometheus data source in Grafana.

What is the default retention in VictoriaMetrics?

One month (31 days), set with -retentionPeriod. The minimum is one day. Open source applies one retention per instance; different retentions per dataset need separate instances or Enterprise.

Should I use the single-node or cluster version?

The documentation recommends single-node below about a million data points per second because it is simpler to run. The cluster version adds horizontal scaling and multi-tenancy.

Can VictoriaMetrics store IoT sensor data?

Yes, for numeric readings. Use stable labels, accept InfluxDB line protocol or remote write from a collector, and buffer at the edge with vmagent. Text values and relational records belong in another store.

Sources

Checked 27 October 2026.

How we research these articles: our editorial method. Research-based from official documentation; SQL examples are run on a local database where the page says so. CodeWithSQL earns nothing from the vendors mentioned.

Building a sensor or telemetry database?

Start with the overview, or compare time-series databases side by side.