Storage bindings

Store exports in R2

Generate a JSON backup and store it as an R2 object instead of placing large binary or file content in D1 or KV.

8 minute lesson

~~~

R2 is object storage for files and large values. Link Vault will write versioned export objects and stream them back on request.

Use a structured object key, set content-type metadata, and stream object bodies instead of buffering unnecessary copies. Store relational metadata in D1 only if the application needs to query exports independently of their object keys.

const key = `exports/${userId}/${crypto.randomUUID()}.json`
await env.EXPORTS.put(key, JSON.stringify({ links }), {
  httpMetadata: { contentType: 'application/json' }
})

An object key is an address, not an authorization rule. Resolve the current user first, then derive or look up only keys that user may access. Do not let an arbitrary path parameter become unrestricted bucket access. Preserve content type and a download filename, and stream object.body so the Worker does not create another full in-memory copy.

Write the object before marking an export ready in D1, or use an intermediate state such as pending. If either operation fails, the state should reveal what can be retried or cleaned up. Retention and deletion are also application behavior: define whether replacing a database record deletes the old object, and test an unknown, unauthorized, and successfully streamed export separately.

Write one export, read it through a protected route, and return 404 for an unknown key.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →