ApiaryActive
Try: pause · settings · learn · wipe
← Community / Reading Room
IR
databases · 12 min read

InfluxDB Retention Policies and Continuous Queries

In the age of IoT, every beehive can be a living laboratory. Sensors record temperature, humidity, weight, acoustic signatures, and even the subtle vibrations…

The data you don’t keep is the data you lose – especially when you’re trying to protect the planet’s most vital pollinators.

In the age of IoT, every beehive can be a living laboratory. Sensors record temperature, humidity, weight, acoustic signatures, and even the subtle vibrations of a queen’s flight. Over weeks, months, and years these measurements become a massive time‑series archive that tells us how climate change, pesticides, and land‑use decisions are affecting bee health.

But raw streams of points quickly become unmanageable. Storing every single reading forever would swamp storage, inflate costs, and drown out the long‑term trends that matter most. That’s where InfluxDB’s retention policies (RPs) and continuous queries (CQs) step in. Together they give you a disciplined, automated pipeline for aging out raw data, pre‑aggregating historic metrics, and keeping the database lean enough to serve real‑time dashboards and AI‑driven decision engines.

In this pillar article we’ll dig deep into the mechanics, best‑practice designs, and concrete examples of using RPs and CQs to turn a noisy hive of sensor data into a tidy, query‑friendly knowledge base. Whether you’re a data engineer building a national bee‑monitoring network, a researcher studying phenology, or an autonomous AI agent tasked with triggering mitigation actions, mastering these tools will let you focus on insights rather than storage headaches.


1. Time‑Series Fundamentals and InfluxDB Basics

InfluxDB is purpose‑built for high‑cardinality, high‑frequency time‑series. Each point consists of:

ComponentDescriptionExample
measurementLogical bucket (e.g., hive_temp)hive_temp
tagsIndexed key‑value pairs for filteringhive_id=42, apiary=NorthField
fieldsNon‑indexed values (the actual data)temp=34.2
timestampNanosecond‑precision UTC time2026‑09‑20T14:03:12Z

A typical beehive sensor might write one point per second for temperature, humidity, and weight, yielding ≈259,200 points per day per hive. Multiply that by 10,000 hives in a national network and you’re looking at 2.6 billion points per day – roughly 30 TB of raw data per month if stored uncompressed.

InfluxDB stores data in shards (time‑range files) that are organized by retention policies. By default a database has a single RP called autogen that retains data forever. That default is convenient for quick experiments but unsustainable for production.

InfluxDB also offers continuous queries, a server‑side mechanism that runs a SELECT statement on a schedule and writes the result into another measurement (often in a longer‑term RP). Think of a CQ as a “cron‑job for aggregates”. In the next sections we’ll see how to harness both features to keep the hive data pipeline tidy, cost‑effective, and ready for AI‑driven analysis.


2. Retention Policies: Concepts, Syntax, and Best Practices

2.1 What Is a Retention Policy?

A retention policy (RP) defines how long InfluxDB keeps data in a given shard. When the retention period expires, the shard is automatically dropped, freeing disk space without any manual intervention.

Key attributes of an RP:

AttributeMeaningTypical Values
durationHow long data lives (e.g., 30d, 90d, INF)30d for raw, 365d for aggregates
replication factorNumber of copies across nodes (clustered setups)1 for single‑node, 3 for HA
defaultWhether new writes default to this RPOnly one RP can be default per DB

2.2 Creating and Managing RPs

-- Create a short‑term RP for raw sensor data (30 days)
CREATE RETENTION POLICY "raw_30d" ON "beehive_db"
DURATION 30d REPLICATION 1 DEFAULT;

-- Create a mid‑term RP for 5‑minute aggregates (180 days)
CREATE RETENTION POLICY "agg_5m_180d" ON "beehive_db"
DURATION 180d REPLICATION 1;

-- Create a long‑term RP for daily rollups (5 years)
CREATE RETENTION POLICY "daily_5y" ON "beehive_db"
DURATION 1825d REPLICATION 1;

Best practice #1 – “Tiered” retention Store raw points in a short‑lived RP, then progressively down‑sample into longer‑lived RPs. This mirrors the way a beekeeper would keep a daily logbook for the current season but archive only monthly summaries for the past decade.

Best practice #2 – Keep the default RP short If you leave autogen as the default, any write that omits an explicit RP will linger forever. Explicitly set a short‑term RP as default (as above) and always reference the target RP in your write APIs.

Best practice #3 – Align RP durations with CQ schedules A CQ that rolls up raw data into a 5‑minute bucket should write into an RP that outlives the source data by at least the CQ’s schedule interval. Otherwise you risk the aggregate being deleted before the source shard is gone, breaking downstream queries.

2.3 Monitoring RP Health

InfluxDB exposes RP metadata via the /query endpoint:

SHOW RETENTION POLICIES ON "beehive_db"

The output includes shard_group_id, duration, and expiry_time. Regularly scrape this data (e.g., with a Prometheus exporter) to alert when a shard is approaching its expiry – a useful safeguard for AI agents that might need to pause ingestion before data loss.


3. Designing Multi‑Tier Retention for Data Aging

3.1 The “Three‑Tier” Blueprint

TierRP NameDurationGranularityTypical Use
Hotraw_30d30 days1‑second pointsReal‑time dashboards, anomaly detection
Warmagg_5m_180d180 days5‑minute averagesTrend analysis, model training
Colddaily_5y5 yearsDaily min/max/meanHistorical research, policy reporting

Why three tiers?

  • Hot tier preserves the fidelity needed for machine‑learning pipelines that ingest recent data (e.g., an AI agent that predicts colony collapse within the next 48 h).
  • Warm tier reduces storage by a factor of ~300 (1 s → 5 min) while still supporting most operational queries.
  • Cold tier shrinks further, enabling multi‑year longitudinal studies without overwhelming the cluster.

3.2 Calculating Storage Savings

Assume each point occupies 30 bytes after compression (typical for InfluxDB line protocol with tags). For a single hive:

TierPoints per dayBytes per dayBytes per year
Raw (1 s)86,4002.6 MB950 MB
5‑min avg2888.6 KB3.1 MB
Daily rollup130 B11 KB

Multiplying by 10,000 hives yields:

  • Raw tier: ~9.5 TB per year
  • Warm tier: ~31 GB per year
  • Cold tier: ~110 MB per year

The three‑tier design reduces total storage from ≈9.5 TB to ≈9.6 TB (a ≈99% reduction) while still preserving the analytical value of historic data.

3.3 Edge Cases – Gaps and Out‑of‑Order Writes

Bees can wander, sensors can reboot, and network partitions can cause late arrivals. InfluxDB’s max-series-per-database and max-values-per-tag settings help guard against tag explosion, but for retention you should also:

  • Enable allow-queries-after-write-failure to keep the pipeline alive.
  • Use precision flags in writes to force nanosecond precision only when needed; coarser timestamps reduce shard count.
  • Set max-age on the line protocol client to drop points older than the raw RP duration (e.g., max-age=30d).

4. Continuous Queries: Real‑Time Aggregation Mechanics

4.1 Anatomy of a Continuous Query

A CQ is defined by three parts:

  1. Name – unique identifier.
  2. SELECT statement – the aggregation you want.
  3. INTO clause – target measurement (and optionally RP).
  4. GROUP BY time() – bucket size and optional tag grouping.
  5. RESAMPLE (optional) – controls execution frequency and look‑back window.

Example – 5‑minute average temperature per hive:

CREATE CONTINUOUS QUERY "cq_temp_5m" ON "beehive_db"
BEGIN
  SELECT mean("temp") AS "temp_avg"
  INTO "agg_5m_180d"."hive_temp_5m"
  FROM "raw_30d"."hive_temp"
  GROUP BY time(5m), "hive_id", "apiary"
END

Key points:

  • The source measurement (hive_temp) lives in the source RP (raw_30d).
  • The target measurement (hive_temp_5m) lives in the target RP (agg_5m_180d).
  • The CQ runs every 5 minutes by default (the bucket size).

4.2 Scheduling and the RESAMPLE Clause

By default, a CQ fires once per bucket after the bucket closes. For high‑frequency data you may want a sliding window:

CREATE CONTINUOUS QUERY "cq_temp_5m_sliding" ON "beehive_db"
RESAMPLE EVERY 1m FOR 5m
BEGIN
  SELECT mean("temp") AS "temp_avg"
  INTO "agg_5m_180d"."hive_temp_5m"
  FROM "raw_30d"."hive_temp"
  GROUP BY time(5m), "hive_id", "apiary"
END

RESAMPLE EVERY 1m FOR 5m tells InfluxDB to recompute the 5‑minute bucket every minute, using the last 5 minutes of data. This reduces latency for alerting agents that need near‑real‑time trends.

4.3 Handling Late Data

InfluxDB’s fill(null) behavior means that if a point arrives after its bucket closed, the bucket will not be recomputed unless you use RESAMPLE. Late data is common in remote apiaries where cellular connectivity is intermittent. A CQ with a generous FOR window (e.g., FOR 30m) will capture most delayed points without overloading the system.

4.4 Performance Considerations

  • Shard selection: CQs only scan shards that intersect the bucket’s time range. Keeping the raw RP short (30 d) ensures each CQ touches a limited number of shards.
  • Tag cardinality: Grouping by high‑cardinality tags (e.g., a unique sensor ID per hive) multiplies the number of series created in the target measurement. Limit grouping to stable tags like hive_id and apiary.
  • Write amplification: Each CQ generates a write for every bucket. For 10,000 hives, a 5‑minute CQ creates 2,880 writes per hour. InfluxDB can handle this easily, but you should monitor write latency (write_latency_ms) and consider batching via the line protocol’s batch_size setting.

5. Combining Retention Policies and Continuous Queries – A Full Workflow

Below is a step‑by‑step recipe that a data‑ops team can copy‑paste into an initialization script.

-- 1️⃣ Create the database (if not exists)
CREATE DATABASE "beehive_db";

-- 2️⃣ Define retention policies
CREATE RETENTION POLICY "raw_30d" ON "beehive_db"
  DURATION 30d REPLICATION 1 DEFAULT;

CREATE RETENTION POLICY "agg_5m_180d" ON "beehive_db"
  DURATION 180d REPLICATION 1;

CREATE RETENTION POLICY "daily_5y" ON "beehive_db"
  DURATION 1825d REPLICATION 1;

-- 3️⃣ Continuous Query: 5‑minute aggregates
CREATE CONTINUOUS QUERY "cq_hive_temp_5m" ON "beehive_db"
BEGIN
  SELECT mean("temp") AS "temp_avg",
         max("temp") AS "temp_max",
         min("temp") AS "temp_min"
  INTO "agg_5m_180d"."hive_temp_5m"
  FROM "raw_30d"."hive_temp"
  GROUP BY time(5m), "hive_id", "apiary"
END;

-- 4️⃣ Continuous Query: Daily rollups (midnight UTC)
CREATE CONTINUOUS QUERY "cq_hive_temp_daily" ON "beehive_db"
RESAMPLE EVERY 1h FOR 24h
BEGIN
  SELECT mean("temp_avg") AS "temp_daily_mean",
         max("temp_max") AS "temp_daily_max",
         min("temp_min") AS "temp_daily_min"
  INTO "daily_5y"."hive_temp_daily"
  FROM "agg_5m_180d"."hive_temp_5m"
  GROUP BY time(1d), "hive_id", "apiary"
END;

Explanation of the flow

  1. Raw ingestion lands in raw_30d. Sensors push a point every second, so the hot tier holds the most granular view for the last month.
  2. CQ #3 rolls those points into 5‑minute buckets stored in agg_5m_180d. The bucket includes average, max, and min – enough for most operational dashboards.
  3. CQ #4 further compresses the 5‑minute aggregates into daily statistics kept for five years. The RESAMPLE EVERY 1h FOR 24h ensures that any late‑arriving 5‑minute bucket (perhaps due to a temporary network outage) still makes it into the daily rollup.

5.1 Integrating an AI Agent

Suppose you have an autonomous AI agent that monitors hive health and triggers interventions (e.g., deploying a mite‑treatment drone). The agent can query the warm tier (agg_5m_180d) for recent trends and the cold tier (daily_5y) for seasonal baselines. Because the data is already pre‑aggregated, the agent can compute a z‑score in milliseconds rather than scanning billions of raw points.

// Example Flux snippet used by the AI agent
from(bucket: "beehive_db")
  |> range(start: -7d)               // last week
  |> filter(fn: (r) => r._measurement == "hive_temp_5m")
  |> filter(fn: (r) => r.hive_id == "42")
  |> aggregateWindow(every: 1h, fn: mean)
  |> map(fn: (r) => ({ r with z: (r._value - mean(r._value)) / stddev(r._value) }))

The agent can then raise an alert if z > 2.5 for three consecutive hours, prompting a self‑governing response that respects the bee colony’s welfare.


6. Practical Example: Sensor Data from Bee Hives

6.1 The Dataset

TagDescriptionTypical Range
hive_idUnique identifier (e.g., H-0012)1‑9999
apiaryGeographic grouping (e.g., Midwest)10‑50
tempInternal hive temperature (°C)30‑38
humidityRelative humidity (%)40‑80
weightHive weight (kg)20‑70
acousticDecibel level of bee buzz30‑90

Sensors publish a JSON payload every second:

{
  "measurement": "hive_env",
  "tags": { "hive_id": "H-0012", "apiary": "Midwest" },
  "fields": { "temp": 34.7, "humidity": 58, "weight": 45.3, "acoustic": 62 },
  "timestamp": "2026-09-25T12:34:56Z"
}

6.2 Ingestion Pipeline

  1. Edge gateway batches up to 1,000 points and sends them via HTTP line protocol to http://influxdb:8086/write?db=beehive_db&rp=raw_30d.
  2. Write latency is typically 5‑10 ms per batch on a modest VM (2 vCPU, 8 GB RAM).
  3. Back‑pressure is handled by the gateway’s internal queue; if the queue exceeds 10 minutes worth of data, the gateway drops the oldest points – a safety net that prevents the database from being overwhelmed.

6.3 Querying the Warm Tier

A researcher wants to know the average temperature trend over the last 14 days for the “Midwest” apiary:

SELECT mean("temp_avg") 
FROM "agg_5m_180d"."hive_temp_5m"
WHERE "apiary" = 'Midwest' AND time > now() - 14d
GROUP BY time(1d) fill(null);

Result: a compact 14‑row table that can be plotted instantly. No need to scan the raw 1‑second data, saving orders of magnitude in CPU and I/O.

6.4 Alerting with Continuous Queries

A CQ can directly write to a “alerts” measurement when a temperature threshold is breached:

CREATE CONTINUOUS QUERY "cq_temp_alerts" ON "beehive_db"
BEGIN
  SELECT max("temp") AS "temp_max"
  INTO "alerts"."hive_temp_alerts"
  FROM "raw_30d"."hive_temp"
  WHERE temp > 36.5
  GROUP BY time(1m), "hive_id", "apiary"
END;

The alerts measurement lives in a separate RP (alert_7d) that retains only a week of alerts, ensuring the alert log stays lightweight while still providing a complete audit trail for compliance auditors.


7. Monitoring, Maintenance, and Troubleshooting

7.1 Health Dashboards

  • Shard count per RP – visualized via SHOW SHARDS. A sudden increase may indicate a mis‑configured RP duration.
  • CQ execution latency – InfluxDB exposes cq_execution_time_ms per CQ; values > 500 ms suggest the query is scanning too many shards or has high tag cardinality.
  • Disk usage – Track influxdb_storage_bytes and set alerts at 80 % capacity.

7.2 Common Pitfalls

SymptomLikely CauseFix
Old aggregates disappearTarget RP duration shorter than source RPExtend target RP (ALTER RETENTION POLICY … DURATION …)
CQ not firingGROUP BY time() interval larger than source data rangeReduce interval or increase source RP duration
High write latencyTag cardinality explosion (hive_id includes timestamp)Re‑design tags; keep only low‑cardinality tags in measurement
“Shard group not found” errorQuery spans beyond RP’s durationAdjust query time range or create a longer RP for historic queries

7.3 Automated Repairs

You can schedule a Flux task (InfluxDB 2.x) or a Kapacitor job (InfluxDB 1.x) to:

  • Re‑create missing CQs after a node restart.
  • Purge orphaned series that survived RP expiry (using DROP SERIES).

Example Flux task that verifies CQs:

option task = {name: "cq_validator", every: 1h}
import "influxdata/influxdb/v1"

cqs = v1.measurements(bucket: "beehive_db")
  |> filter(fn: (r) => r._measurement =~ /_cq_/)

cqs
  |> map(fn: (r) => ({ r with _value: if exists r._value then "OK" else "MISSING" }))
  |> to(bucket: "monitoring")

8. Scaling Considerations and Performance Tuning

8.1 Horizontal Scaling with InfluxDB Enterprise

When the hive network grows beyond 50,000 sensors, a single node cannot keep up with write throughput (> 500 k points/s). InfluxDB Enterprise lets you:

  • Shard across multiple data nodes – each node handles a subset of time ranges.
  • Set replication factor > 1 – improves fault tolerance for critical RP (e.g., agg_5m_180d).

8.2 Index Management

InfluxDB indexes

Frequently asked
What is InfluxDB Retention Policies and Continuous Queries about?
In the age of IoT, every beehive can be a living laboratory. Sensors record temperature, humidity, weight, acoustic signatures, and even the subtle vibrations…
What should you know about 1. Time‑Series Fundamentals and InfluxDB Basics?
InfluxDB is purpose‑built for high‑cardinality, high‑frequency time‑series . Each point consists of:
2.1 What Is a Retention Policy?
A retention policy (RP) defines how long InfluxDB keeps data in a given shard. When the retention period expires, the shard is automatically dropped, freeing disk space without any manual intervention.
What should you know about 2.2 Creating and Managing RPs?
Best practice #1 – “Tiered” retention Store raw points in a short‑lived RP, then progressively down‑sample into longer‑lived RPs. This mirrors the way a beekeeper would keep a daily logbook for the current season but archive only monthly summaries for the past decade.
What should you know about 2.3 Monitoring RP Health?
InfluxDB exposes RP metadata via the /query endpoint:
References & sources
  1. Apiary Reading Room — Open, cited knowledge base — funded to keep bee & practical research free.
From the Apiary Reading Room. Opinion & editorial — not financial advice. We don't overclaim.
More from the Reading Room