Data Retention
Heartbeet automatically deletes old event data to manage database storage and respect plan limits.
Retention windows
| Plan | Event retention |
|---|---|
| Free | 30 days |
| Starter | 1 year (365 days) |
| Pro | 3 years (1,095 days) |
| Enterprise | 3 years (1,095 days) |
How it works
The cron job (/api/cron/analyze) runs a cleanup function at the start of each hourly run. It calls the cleanup_old_beet_events() PostgreSQL function, which deletes events from beet_events where received_at is older than the organisation’s retention window.
-- Simplified version of the cleanup logic
delete from beet_events e
using beets b
join projects p on p.id = b.project_id
join organizations o on o.id = p.org_id
where e.beet_id = b.id
and e.received_at < now() - (
case o.plan
when 'free' then interval '30 days'
when 'starter' then interval '365 days'
else interval '1095 days'
end
);Baseline data
Baselines (beet_baselines_hourly) are not subject to the same retention window. They represent aggregated statistics, not raw events, and are retained indefinitely. This ensures that a beet that has been running for years maintains its full historical baseline even on the Free plan.
Partition-aware deletion
The beet_events table is partitioned by received_at (monthly partitions). The DELETE query against a partitioned table allows Postgres to eliminate entire partitions that fall outside the retention window, making cleanup very efficient even at high data volumes.
Impact of plan downgrades
If an organisation downgrades (e.g. from Starter to Free), events older than 30 days will be deleted on the next cron run. This cannot be reversed. Baselines are preserved.