# Data files `ctx.data` gives [functions](/functions) and [cron jobs](/cron-jobs) a simple, file-native persistence layer under `/data/`. It's the fastest way to store settings, drafts, text, and simple event logs without provisioning a database. Use Data files when your application state naturally belongs in a text, JSON, or JSONL file and writes are infrequent. For structured application data, queries, relationships, counters, or concurrent updates, use a [Database](/databases). Data files are ordinary site files: visible to authenticated tooling, but never served on public hosted URLs. ## Storage usage and billing File storage is measured across your account by file size and time retained. Static files, `/data` files, function source, and cron source count, including files on archived sites. Deleting a file stops its contribution. Historical revisions are currently excluded from customer storage usage. The retention and pricing policy for retained history is under review. Free includes 1 GB; monthly Builder includes 25 GB. New Builder subscriptions include storage overage billing. For activated subscriptions, overage costs **$0.030666… per GB-month** after the included allowance, billed with your subscription. One GB is 1,073,741,824 bytes; a month is your actual subscription billing period. Request costs are included in this storage rate. The allowance is applied once to the period's size × time usage. For example, 100 GB retained for an entire Builder billing period produces 75 GB-month of overage, or **$2.30** before taxes and discounts. Activation starts measurement from that point forward; earlier usage is not backfilled. See **Usage → File storage** in the [dashboard](https://app.interfold.dev/usage) for stored bytes, included storage, estimated overage, and whether billing is active. Existing subscriptions without storage billing attached remain inactive. ## Helpers Inside a function or cron handler, reach for `ctx.data`: ```ts // Text await ctx.data.read('/data/notes.txt') await ctx.data.write('/data/notes.txt', 'hello') await ctx.data.delete('/data/notes.txt') await ctx.data.info('/data/notes.txt') // JSON await ctx.data.readJson('/data/settings.json') await ctx.data.writeJson('/data/settings.json', { theme: 'dark' }) // JSONL (append-only logs) await ctx.data.appendJsonl('/data/events.jsonl', { type: 'created' }) await ctx.data.tailJsonl('/data/events.jsonl', 100) ``` ## Extension rules The structured helpers require matching file extensions: | Helper | Required extension | | -------------------------- | ------------------ | | `readJson`, `writeJson` | `.json` | | `appendJsonl`, `tailJsonl` | `.jsonl` | | `read`, `write` | any | ## Patterns ### JSON document A single evolving document — settings, a small record, aggregate state: ```ts export async function handler(req: Request, ctx: InterfoldContext) { const settings = await ctx.data .readJson('/data/settings.json') .catch(() => ({ theme: 'light' })) return Response.json(settings) } ``` ### JSONL event log Append-only records — form submissions, analytics, audit trails: ```ts export async function handler(req: Request, ctx: InterfoldContext) { await ctx.data.appendJsonl('/data/signups.jsonl', { email: (await req.json()).email, at: new Date().toISOString(), }) const recent = await ctx.data.tailJsonl('/data/signups.jsonl', 20) return Response.json({ recent }) } ``` ## Concurrency Data file writes create file revisions. The Files API and MCP can reject a stale replacement when given the current version ID. `ctx.data` uses version checks for its read-modify-write operations. For shared state needing transactions across records, use a [Database](/databases). For logs, drafts, settings, and other low-contention state, `ctx.data` is ideal. ## Inspecting data Data lives at `/data/*` and is not a public URL. Read it with authenticated tooling: ```sh interfold files ls /data --site interfold files cat /data/settings.json --site ``` --- Next: [Databases](/databases) for structured application data · [Secrets](/secrets) for runtime configuration.