# Keep the datafile at your edge (/docs/guides/datafile-at-the-edge)

Every visit that uses Improve needs the datafile: the client SDK requests `/config/…` per page view, and a server render fetches it when its copy is missing. Each request carries the tests, flags and audiences for that environment. Cloudflare caches the response for 30 seconds and can serve it stale for another 60, so most never reach the database — but each one still counts as a datafile request, and a render that misses the cache waits on it.

You can take that request off the render path. Keep a copy of the datafile in storage you own — Workers KV, an R2 bucket, Vercel Global Config, Redis — and read that copy instead. This page is the shape of the setup and what it costs in requests; [Cloudflare KV](/docs/integrations/cloudflare-kv) is the worked example.

## What you gain [#what-you-gain]

- **Renders read local storage.** No subrequest, no timeout to handle, no dependency on Improve being reachable at that moment.
- **Requests stop following traffic.** A copy polled every five minutes makes about 8,600 requests a month whatever your traffic is. Loading it per visitor makes as many requests as you have visitors.
- **Flags and tests keep working during an Improve incident.** They evaluate from the last copy.

## What you give up [#what-you-give-up]

- **Changes arrive on your schedule.** An edit no longer reaches visitors within Improve's ~90-second edge window; it reaches them on the next poll, plus your store's own propagation.
- **You own the sync.** A scheduled Worker (or a build step) that fetches the datafile and writes it, and the store it writes to.
- **Only `active` travels.** Drafts and the other states stay on the API for previewing.
- **The copy is only as good as its last write.** A failed poll must leave the previous datafile in place, never an empty one.

## How stale can it get? [#how-stale-can-it-get]

Three windows add up:

1. Improve's edge cache: a poll can receive a copy up to 90 seconds old (30 seconds fresh, then up to 60 served stale while it refreshes).
2. Your poll interval.
3. Your store's propagation. Workers KV usually shows a write everywhere within 60 seconds.

| Poll interval | Worst-case staleness | Checks per day | Checks per month |
| ------------- | -------------------- | -------------- | ---------------- |
| 1 minute      | ~3.5 minutes         | 1,440          | 43,200           |
| 5 minutes     | ~7.5 minutes         | 288            | 8,640            |
| 15 minutes    | ~17.5 minutes        | 96             | 2,880            |
| 1 hour        | ~62 minutes          | 24             | 720              |

The counts are per environment. Syncing develop, staging and production for one Space multiplies them by three, and every environment draws on the organization's one datafile allowance.

A five-minute poll gives you flags that are minutes old, not seconds. For a rollout that is usually fine. For a kill switch it is not: poll every minute, or keep a direct read on the path that checks the flag.

## What it costs in requests [#what-it-costs-in-requests]

This is the number to check before you switch.

Without a copy, every datafile request counts against your allowance — including the ones Cloudflare answers from its cache ([rate limits and quotas](/docs/api#rate-limits--quotas)). At 100,000 page views a month, that is about 100,000 datafile requests.

With the five-minute poll above, it is 8,640: about 91% fewer, and flat as traffic grows. At 10,000 page views a month, one environment's poll is 8,640 against 10,000 — the copy still wins, but only just. The break-even is your monthly page views against the `checks per month` column.

The poll is one scheduled invocation per tick, plus one read from your store per render. On Improve it is one datafile request per environment per tick, which is what the table counts.

## Where the copy can live [#where-the-copy-can-live]

| Store                | Read                    | Note                                                                                                         |
| -------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------ |
| Workers KV           | binding                 | Closest to the Worker and cheapest per read. A write usually shows everywhere within 60s.                    |
| R2                   | binding                 | Strongly consistent; put `caches.default` in front of the read.                                              |
| Vercel Global Config | `@vercel/global-config` | [Improve mirrors](/docs/integrations/vercel) a connected Space's datafile here; write it yourself otherwise. |
| Redis, S3, a table   | your client             | Anywhere else. The sync is the same; only the write changes.                                                 |
| A file in your repo  | build step              | No runtime store. The copy changes when you deploy.                                                          |

The sync is the same in every case: fetch the datafile, write it whole, keep the last good copy. On Vercel you don't have to write it at all — connecting the Space mirrors all three environments for you ([Vercel](/docs/integrations/vercel)).

## Keeping it correct [#keeping-it-correct]

- **One key per Space and environment** (`improve/org_…/production`), not one per test or flag. The datafile is the unit that changes, so one key writes atomically.
- **Compare before writing.** A five-minute poll writes 288 times a day even when nothing changed, and writes are the expensive half of KV. Skip the write when the body is identical.
- **Keep the old value on a failed poll.** A non-2xx response, a timeout or a parse error is not a reason to delete what you have.
- **Fill it on deploy too.** A cron may not fire for minutes, and a new environment has no key at all.
- **Don't expose the store.** The datafile itself is public (anyone who knows the id can fetch it without an `Origin`), but a KV namespace read through a binding needs no route, so there is nothing to publish.

## Before you build it [#before-you-build-it]

Two things decide whether this is worth it:

- **Your page views against the table.** Below a few thousand a month, the poll can cost more requests than the renders it replaces.
- **How fast a flag has to change.** If the answer is seconds, keep the datafile request and use this only for the flags that can lag.
