When to re-geocode your database: a lifecycle policy

Geocoded data ages silently. Learn the four triggers, cadence tiers, and confidence-delta method that tell you exactly when to re-geocode your database.

| August 25, 2026
When to re-geocode your database: a lifecycle policy

There is a class of data-quality problem that never throws an exception. No alert fires, no dashboard turns red, no on-call engineer gets paged. The data just silently becomes wrong, and the business finds out six months later when a delivery driver reports an address that does not exist, or when a risk model trained on five-year-old coordinates starts producing nonsense for a neighbourhood that has been entirely rebuilt.

That is geocoded data ageing.

The instinct after a large geocoding project is to cache the results and move on. That instinct is mostly correct — caching is efficient, and the 90% cost-reduction case for aggressive caching is real and worth reading. But "cache forever" is the wrong policy when the source addresses themselves are changing. The question is not *whether* to re-geocode; it is *when*, *which records first*, and *how to measure whether the run actually improved things*.

This post answers all three.

Why geocoded data ages

Coordinates do not move. The lat/lng pair you stored for a warehouse address three years ago still points to the same physical spot on the planet. What changes is the *mapping from address string to coordinate* — and that mapping is live, messy, and continuously updated by the agencies, carriers, and municipal databases that underpin any geocoding system.

Four mechanisms drive the drift.

New construction. A development of three hundred homes is permitted, built, and occupied. Each unit receives a new postal address that did not exist when you last geocoded. If your customer table contains any of those addresses typed in at onboarding, their rows either failed to geocode at the time (returning no result) or resolved to the nearest existing centroid — which might be the plot boundary, the street intersection, or the general postcode rather than the front door. A re-geocoding pass eighteen months after the development's completion will resolve those rows correctly.

Street renames and postcode reassignments. Municipalities rename roads for commemorative, safety, or administrative reasons. Postcode boundaries get redrawn when a sorting office changes routing. An address that was unambiguously correct when you stored it may now resolve to a different coordinate — or fail to resolve at all — because the canonical form has changed. These events are rare per-address, but at warehouse scale they accumulate steadily.

Geocoder improvement. The dataset underlying a geocoding service grows continuously. An address that returned a low-confidence result eighteen months ago because it was new or poorly matched may now resolve with high confidence because the reference data has caught up. Re-geocoding low-confidence records is a guaranteed-ROI operation: you are spending a small number of credits on rows that are almost certainly wrong, and a successful resolution is a concrete data-quality improvement.

Observed operational failures. A delivery fails. A route optimiser cannot find a stop. A mailing comes back undeliverable. Each of these is a signal — noisy but real — that the coordinate for that record may be wrong. These events should feed directly into your re-geocoding queue.

None of these mechanisms are things you can measure by looking at your data in isolation. The data does not know it is wrong. The mechanism for discovering the problem is a periodic re-geocoding pass that compares the new result against the stored result and surfaces discrepancies.

The four triggers

A practical re-geocoding policy has triggers at four levels. You do not re-geocode everything at once; you re-geocode in priority order.

Trigger 1: Record age

Any coordinate older than a defined threshold gets queued for re-geocoding at the next scheduled run. The right threshold depends on how dynamic your address universe is — a database of US residential delivery addresses changes faster than a database of commercial real-estate parcels. Start with a conservative threshold (two to three years) and tune based on what your confidence-delta measurements tell you (more on that below). Do not apply a single threshold to the whole warehouse; segment by record type.

Trigger 2: Low original confidence score

If you stored the confidence score at geocoding time — and you should have; see Geocoding Confidence Scores Explained — then every record below a threshold (0.7 is a reasonable starting point) is a re-geocoding candidate regardless of age. These records were uncertain at the time you geocoded them. Re-geocoding them now costs one credit per address and has a real probability of returning a better result.

Records with confidence below 0.5 at original geocoding time are essentially placeholders. They should be re-geocoded on every scheduled cycle until they either resolve with high confidence or are flagged for manual review.

Trigger 3: High-value records

Some records carry enough business weight that you want the coordinates to be correct even if the current result looks fine. A policy address for a high-replacement-cost property, a principal customer location that drives routing for hundreds of deliveries per week, a care-home address in a patient-record system — these deserve periodic re-geocoding regardless of their confidence score or age, because the cost of an error in these rows is disproportionately high.

Identify the top percentile of records by business value in your warehouse, add a high_value flag, and include them in every scheduled re-geocoding cycle. The number of such records is usually small relative to the full warehouse; the incremental cost is trivial.

Trigger 4: Observed delivery failures

Wire your operational failure signals into your data pipeline. When a delivery scan returns "address not found", when a postage item is returned undeliverable, when a patient's discharge letter bounces — that event should write a re_geocode_queued = true flag to the corresponding record within the same pipeline. This turns your operational data into a live signal about geocoding quality and ensures that known-bad records are corrected in the next scheduled run rather than continuing to fail indefinitely.

Cadence tiers

Not every record needs re-geocoding on the same schedule. Applying a single cadence to a warehouse of five million addresses is expensive and unnecessary. Tier the cadence by trigger type.

Tier 1 — Monthly: Records flagged by trigger 4 (observed failures) and records with original confidence below 0.5. These are actively hurting your operations. Run them every month until they resolve or are escalated to manual review.

Tier 2 — Quarterly: Records with original confidence between 0.5 and 0.7, records flagged as high-value (trigger 3). These are uncertain or important. Quarterly re-geocoding catches geocoder improvements as the underlying reference data grows, without the cost of monthly runs.

Tier 3 — Annual: Records with original confidence above 0.7 that are older than your age threshold (trigger 1). The majority of your warehouse. An annual re-geocoding pass finds the accumulated drift from new construction and street renames, at the lowest possible cost per record.

Never scheduled: Records geocoded in the last ninety days with confidence above 0.8. These are fresh and good. Leave them alone — this is where the caching argument wins outright.

The tiered approach means your monthly re-geocoding job might touch 2% of the warehouse, your quarterly job another 8%, and the annual job covers the rest. At any given time, only a small fraction of the warehouse is being actively re-geocoded.

Measuring improvement: the confidence-score delta

Re-geocoding without measurement is spending credits without knowing whether anything improved. The right instrument is the confidence-score delta between runs.

For every record that goes through a re-geocoding pass, store:

original_confidence   (from the first geocoding run)
latest_confidence     (from this run)
confidence_delta      = latest_confidence - original_confidence
lat_delta_m           = haversine distance between old and new coordinates, in metres
geocoded_at           (timestamp of this run)

Aggregate these metrics per re-geocoding batch and you get a real measurement of improvement. A batch where the median confidence_delta is +0.15 and 12% of records moved more than 50 metres is a batch that did real work — it corrected records that were materially wrong. A batch where the median delta is +0.01 and fewer than 1% of records moved at all is a batch that confirmed your existing data is mostly fine, which is also useful information.

The lat_delta_m field is particularly valuable. A record where the coordinate moved 500 metres is a record that was definitely wrong before — the geocoder previously resolved it to a street centroid or a postcode polygon, and now it has a rooftop-level match. A record that moved 3 metres moved within the noise of the geocoder's internal precision. Both are correct; they tell you different things about data quality.

Run this measurement report after every re-geocoding batch. Share it with your data engineering stakeholders as a concrete quality metric. "This quarter's re-geocoding pass improved the median confidence of our low-confidence tier by 0.18 points and corrected 3,400 records that had moved more than 100 metres" is a defensible line item in a data-quality programme.

How to run a re-geocoding pass with the batch tool

CSV2GEO's web batch tool is the right surface for periodic re-geocoding runs. The billing model is per address row — you pay for the rows you submit, not for the columns you send. That means you can enrich your submission with metadata (record IDs, original confidence scores, geocoded-at timestamps) as extra columns and the credit cost is unchanged.

The workflow for a monthly Tier 1 re-geocoding pass looks like this in practice.

Step 1: Export the candidate records

Query your warehouse for records matching your trigger criteria. The output CSV should include enough columns to re-link results back to your source records: record_id, address, original_confidence, original_lat, original_lng, geocoded_at.

import csv
import os
import requests

# Export query result to candidates.csv (your warehouse query here)
# candidates.csv: record_id, address, original_confidence, original_lat, original_lng

with open("candidates.csv", newline="") as f:
    reader = csv.DictReader(f)
    candidates = list(reader)

print(f"{len(candidates)} records queued for re-geocoding")

Keep the record_id column. The entire value of using stable keys is that re-geocoding *updates* existing records rather than creating duplicates. Without a stable key in the output, you cannot join the new results back to the right rows.

Step 2: Submit to the batch endpoint

The batch geocoding endpoint accepts a CSV upload. Pass the address column as the geocodable field. The API returns a result row for each input row, preserving order so you can zip() the input and output back together.

API = "https://csv2geo.com/api/v1/geocode/batch"
KEY = os.environ["CSV2GEO_API_KEY"]

with open("candidates.csv", "rb") as f:
    resp = requests.post(
        API,
        params={"api_key": KEY, "address_col": "address"},
        files={"file": ("candidates.csv", f, "text/csv")},
        timeout=120,
    )
    resp.raise_for_status()
    result = resp.json()

print(f"Job ID: {result['job_id']} — status: {result['status']}")

Or in Node:

import { createReadStream } from 'node:fs';
import FormData from 'form-data';

const API = 'https://csv2geo.com/api/v1/geocode/batch';
const KEY = process.env.CSV2GEO_API_KEY;

const form = new FormData();
form.append('file', createReadStream('candidates.csv'), { filename: 'candidates.csv' });

const resp = await fetch(`${API}?api_key=${KEY}&address_col=address`, {
  method: 'POST',
  body: form,
  headers: form.getHeaders(),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const result = await resp.json();
console.log(`Job ID: ${result.job_id} — status: ${result.status}`);

Large batches are processed asynchronously. Poll the job status endpoint until status is complete, then download the result CSV.

Step 3: Download results and compute deltas

import math

def haversine_m(lat1, lng1, lat2, lng2):
    R = 6_371_000
    phi1, phi2 = math.radians(lat1), math.radians(lat2)
    dphi = math.radians(lat2 - lat1)
    dlam = math.radians(lng2 - lng1)
    a = math.sin(dphi/2)**2 + math.cos(phi1)*math.cos(phi2)*math.sin(dlam/2)**2
    return R * 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))

# Download result CSV from job (polling omitted for brevity)
with open("result.csv", newline="") as f:
    results = list(csv.DictReader(f))

deltas = []
for orig, new in zip(candidates, results):
    conf_delta = float(new["confidence"]) - float(orig["original_confidence"])
    dist_m = haversine_m(
        float(orig["original_lat"]), float(orig["original_lng"]),
        float(new["lat"]), float(new["lng"])
    )
    deltas.append({
        "record_id": orig["record_id"],
        "new_lat": new["lat"],
        "new_lng": new["lng"],
        "new_confidence": new["confidence"],
        "confidence_delta": conf_delta,
        "lat_delta_m": dist_m,
    })

improved = [d for d in deltas if d["confidence_delta"] > 0.05 or d["lat_delta_m"] > 50]
print(f"{len(improved)} records materially improved")

The improved list is the set of records worth updating in your warehouse. Records that neither improved in confidence nor moved meaningfully can be left as-is — you have confirmed they are stable.

Step 4: Apply updates back to the warehouse

Use your record_id stable key to UPDATE rather than INSERT. This is the critical operational difference between a re-geocoding policy and a naive re-import.

import sqlite3  # substitute your actual warehouse connector

conn = sqlite3.connect("warehouse.db")
cursor = conn.cursor()

for d in improved:
    cursor.execute("""
        UPDATE addresses
        SET lat = ?, lng = ?, confidence = ?, geocoded_at = CURRENT_TIMESTAMP
        WHERE record_id = ?
    """, (d["new_lat"], d["new_lng"], d["new_confidence"], d["record_id"]))

conn.commit()
print(f"Updated {cursor.rowcount} records")

Log the confidence_delta and lat_delta_m distributions to your observability stack — these are the quality metrics that justify the next budget cycle's re-geocoding spend. For a deeper look at what to instrument, see Observability for Geocoding Pipelines.

Step 5: Update re-geocoding metadata and schedule the next run

After a successful pass, update each processed record's last_re_geocoded_at timestamp and reset re_geocode_queued to false. Records that still return low confidence after re-geocoding should be escalated: set a manual_review_required flag and surface them in your data-quality dashboard. They may have genuinely ambiguous addresses that no geocoder can resolve without human input.

Schedule the next pass based on your cadence-tier logic. A cron expression or a dbt model that writes re_geocode_queued = true to records crossing their age or confidence threshold is the right automation surface — re-geocoding should happen automatically, not because someone remembered to kick off a script.

Cost maths for a real-world warehouse

A concrete example. Assume a warehouse of 500,000 address records, typical of a mid-sized logistics or insurance operation.

Tier distribution (illustrative):

  • Tier 1 (monthly, low confidence + failures): ~10,000 records = 10,000 credits/month
  • Tier 2 (quarterly, uncertain + high-value): ~40,000 records = 40,000 credits/quarter = ~13,300 credits/month
  • Tier 3 (annual, the rest): ~450,000 records = 450,000 credits/year = ~37,500 credits/month

Total average monthly credit consumption for re-geocoding: roughly 61,000 credits.

At the entry paid tier ($54/month for 100,000 calls), the entire re-geocoding programme for a 500,000-record warehouse fits comfortably within a single plan bracket, with credits left over for live operational geocoding during the month. At scale, the per-record annual re-geocoding cost is well under a fraction of a cent.

The free tier — 3,000 calls per day — is sufficient to run a pilot on a 3,000-record sample before committing to a paid plan. Use the pilot to measure your own confidence-delta distribution. That measurement is worth more than any benchmark I could quote: it tells you specifically how much drift has accumulated in your data, and it gives you the numbers to defend the re-geocoding budget internally.

See the live pricing brackets at csv2geo.com/pricing/api.

This post is the counterweight to "cache forever"

Caching is correct. Caching geocoding results aggressively reduces costs and improves pipeline throughput — read the full caching argument if you have not already. But a cache that never invalidates is a liability in a changing address universe.

The resolution is not "cache less" — it is "cache with a defined expiry that maps to your re-geocoding cadence." A record in Tier 3 (annual re-geocoding) should be cached for twelve months. A record in Tier 1 (monthly re-geocoding) should be cached for thirty days. The cache TTL and the re-geocoding cadence are the same number, expressed in two different systems.

When the re-geocoding pass returns an improved result, invalidate the cache entry for that record. The next request gets a fresh lookup from the warehouse, and the cycle continues. This is a complete lifecycle policy, not a one-time migration.

Frequently Asked Questions

How do I know if my data has drifted without running a full re-geocoding pass?

Sample 500–1,000 records at random, stratified by age and original confidence. Re-geocode that sample and compute the confidence-delta and lat-delta distributions. The sample statistics are a reliable proxy for the full warehouse. If your sample shows a median lat-delta above 30 metres or a meaningful fraction of records with confidence improvements above 0.1, the drift is real and a full pass is justified.

Should I re-geocode records that have high original confidence?

Not on a short cycle. High-confidence records in Tier 3 should be re-geocoded annually — not because they are likely wrong, but because annual re-geocoding catches the rare cases where a street rename or postcode reassignment has shifted the canonical form of the address. The cost per record is one credit once per year, which is negligible at any sensible volume.

What if re-geocoding returns a lower confidence than the original result?

This happens when the geocoder's reference data has changed and the match that previously looked solid is now ambiguous — for example, a street that was renamed and the old name is no longer a primary key. Do not automatically overwrite the stored coordinate with a lower-confidence result. Write the new result to a staging column, flag the record for review, and let a human decide which result to keep.

How does the batch tool billing work for re-geocoding?

Credits are consumed per address row submitted. There is no discount for re-geocoding versus first-time geocoding — the API does not know whether a record has been geocoded before, and that is fine. Your cost control comes from tiering: only submit the records that actually need re-geocoding on each cycle, not the full warehouse.

Can I run re-geocoding in parallel with live operational geocoding on the same API key?

Yes. The API key has a rate limit; large re-geocoding batches should be submitted via the batch endpoint (which processes server-side without consuming your real-time rate limit) rather than as individual calls. If you are running individual calls in a nightly job, implement concurrency control so the re-geocoding job does not saturate the rate limit and starve your operational pipeline.

What is a reasonable minimum sample size for a confidence-delta pilot?

Five hundred records is the practical minimum for a meaningful distribution. A thousand records is better. Stratify the sample by age bucket (0–6 months, 6–18 months, 18–36 months, 36+ months) and by original confidence tier — the delta is not uniform across these groups, and a stratified sample tells you which tier has the most drift and therefore the most value from re-geocoding.

Do I need stable record keys for re-geocoding to work?

You need them for re-geocoding to be operationally clean. Without a stable key on each record, the only way to apply updated coordinates back to your warehouse is a full re-import or a fuzzy-match join on the address string — both of which are error-prone. If your current schema does not have a stable geocoding key, add one before you run your first re-geocoding pass. The deduplication and stable-key pattern is covered in the caching post linked above.

Related Articles

---

*I.A. / CSV2GEO Creator*

Ready to geocode your addresses?

Use our batch geocoding tool to convert thousands of addresses to coordinates in minutes. Start with 100 free addresses.

Try Batch Geocoding Free →