The short version: We moved five years of Home Assistant history — more than 400 million data points — out of the InfluxDB 1.x add-on and onto a dedicated InfluxDB 2.x server, without losing a single point and without rewriting a single Grafana dashboard. Three phases, one seam, zero drama.
This is the story of that migration: how we planned it in phases, which pitfalls nearly bit us, and what we’d do differently if we had to do it again (and what we’d do exactly the same).
Why migrate at all?
The add-on served us well, but three things pushed us over the edge:
- Coupling. InfluxDB lived inside Home Assistant. Any HA restart, add-on update, or disk hiccup dragged the database with it — and vice versa.
- InfluxDB 1.x is end-of-life. The 2.x line is the present, and the add-on was frozen on old code while our needs kept growing.
- Isolation. A time-series database is a long-lived, disk-hungry service. It deserves its own home, restarts included.
So the goal: new server, same history, same dashboards, zero data loss.
The plan: three phases, no “big bang”
The tempting approach is one big cutover: stop the add-on, export everything, import it, switch HA over. That sounds simple — and it’s exactly how you lose data. A full export of 400M+ rows takes hours, and “now” keeps moving while you work. Anything written after your snapshot becomes a gap.
We split the migration into three phases:
| Phase | What | Data window |
|---|---|---|
| 1. Historical import | Bulk-export all 5 years from the 1.x add-on → import into 2.x | 5 years, the bulk (400M+ rows) |
| 2. Live cutover | Point the HA InfluxDB integration at the new server | Everything from the cutover onward |
| 3. Gap merge | Export + import only the slice between snapshot and cutover | Minutes, ~80k points |
The key insight: only phase 3 is time-critical. Phases 1 and 2 can happen whenever; phase 3 closes the seam.
Phase 1: moving 400M+ rows (the boring, long part)
The tool that matters: influx_inspect
Our first attempt used the add-on container’s regular influx CLI to export
line protocol. It failed immediately — that particular 1.x build simply doesn’t
support the export format we needed. Nothing was damaged, because the script
had a built-in safety gate: it aborted before the import step the moment the
export didn’t produce the expected output.
The tool that actually worked is the one InfluxDB ships for this exact job:
influx_inspect export. It dumps the raw shards straight to line protocol —
no queries, no pagination pain, just a stream.
Reality check: it’s huge
- 402,431,663 rows across 10 measurements (
W,kWh,°C,%,A,bar,hPa,EUR,MAD,m³), each carryingdomain+entity_idtags. - The gzipped export was 2.95 GB. On a small HA disk, that matters.
- Old InfluxDB 1.x timestamps have nanosecond precision — and line protocol
defaults can silently truncate that. We wrote with
precision=nsso every historical timestamp survived bit-for-bit.
Import
Import to the new InfluxDB 2.x server was a straight line-protocol write of the export. Long, boring, and exactly what we wanted: no per-point API calls, one streaming pipe, hours instead of weeks.
Pitfall #1: don’t underestimate the export file — 2.95 GB compressed doesn’t fit everywhere. Check free disk on both hosts before you start.
Pitfall #2: don’t trust the default timestamp precision. If you’re importing decades-grade history, force
precision=ns.
Phase 2: the cutover
With the history safely on the new server, the dramatic part was actually boring by design: we changed the HA InfluxDB integration to point at the new server with a scoped token (read + write on the bucket, nothing else).
The first sign of trouble would have been HTTP 401s in the HA logs — we saw
none. A minute later, new points were landing on the new server. HA wrote
live, and the old add-on quietly went silent.
Phase 3: closing the gap (don’t skip this)
Here’s the part most migration guides forget. Between the moment our snapshot was taken and the moment HA switched over, the old add-on kept receiving live data. If we’d stopped there, that slice would be missing forever.
We exported that window — ~80,337 points — through the read-only v1 HTTP
query API with epoch=ns, gzip-compressed it, and POSTed it to the new server.
Result: 82,489 points on the new server when we verified afterwards
(the difference is the live data that arrived in between).
Closing a data gap of 80k points when your dataset is 400M rows feels anticlimactically small — and that’s the point. That tiny seam is exactly what “zero data loss” means.
The trick that saved our dashboards: v1 compatibility
We expected the worst part to be rewriting Grafana dashboards for InfluxDB 2.x. It wasn’t. InfluxDB 2.x ships a v1-compatible HTTP API, and Grafana can just use it in InfluxQL mode: same queries, same dashboards, zero rewrites.
Every one of our panels — energy, climate, water pressure, exchange rates — kept working the moment the data source pointed at the new host.
Rule of thumb: if you only use InfluxQL, v1-compat means your migration is a server swap, not a query migration. If you wrote custom Flux queries, audit those separately — that’s where the real work hides.
Verification & rollback
Two things we treated as non-negotiable:
- Verify before you celebrate. We checked: measurement count (
SHOW MEASUREMENTS), the newest point (must be “now”), counts on the new server, and spot-checks of real sensor series against the old server. - Keep the old add-on until you’re confident. We only stopped it after everything was green — and we still didn’t delete it. A stopped add-on is a free backup; it can be re-enabled in five minutes if something lurks in your data months later.
That may sound overly cautious for “just a database move.” It’s exactly the caution that makes a 400M-row migration a non-event.
Lessons learned (the honest list)
- Phase it. One mega-cutover on 400M rows is how you get a hole in your history. Import → cutover → gap-merge closes every seam.
- Test the tools in your container first. The add-on didn’t support the export format we assumed. We found out safely only because of a dry-run safety gate before any import.
- Watch the disk twice. Export file on the old host, new database on the new host — both need headroom. 2.95 GB compressed ≠ 3 GB uncompressed.
- Timestamps have feelings too. Nanosecond precision is real in old data;
write with
precision=nsor silently round your history. - The gap is the enemy, not the big numbers. The scary moment is the minutes between snapshot and cutover, not the 400M rows.
- Use scoped tokens. The new server’s token has read+write on exactly one bucket — nothing more.
- v1-compat is your friend. It turned a potentially hair-raising Grafana rewrite into “point the data source elsewhere.”
- Keep the old add-on. Stop it, don’t delete it. Rollback insurance costs nothing and is worth everything.
What happened after
The old add-on now sits stopped — a silent backup. The HA box got 2.95 GB
freed (the export archive lived on its /share, and is gone now that the
new server is verified). We kept a lightweight read-only health check that
runs a few times a day: it confirms the new server responds, Grafana responds,
and — most importantly — that Home Assistant is still writing and the newest
point is never more than an hour old. If the old add-on ever wakes back up, we
want to know immediately.
Five years. Four hundred million rows. One seam, closed with ~80k points. New server, same history, same dashboards, still live.
That’s how you move a smart home’s memory.