---
title: Choose storage
description: The storage backends the server supports, which one to pick, and the order in which the server picks one.
---

The server stores artifacts through [Files SDK](https://files-sdk.dev). It has three built-in backends and a hook for any other Files SDK adapter.

| Backend                                   | Configure it with                           | Runs on                |
| ----------------------------------------- | ------------------------------------------- | ---------------------- |
| [Cloudflare R2](/storage/r2)              | An `R2_STORE` binding                       | Cloudflare Workers     |
| [Cloudflare KV](/storage/kv)              | A `KV_STORE` binding                        | Cloudflare Workers     |
| [S3-compatible bucket](/storage/s3)       | `S3_BUCKET`, `S3_ENDPOINT`, and credentials | Every platform         |
| [Custom adapter](/storage/custom-adapter) | Code in `apps/api/src/custom-adapter.ts`    | Depends on the adapter |

## Which one to pick

On Cloudflare Workers, use R2. It is the default, it needs no credentials, and it stores any artifact the Worker accepts. Choose KV only if every artifact is under 25 MiB and you can accept that a new artifact can take a minute or more to reach other regions.

On any other platform, use an S3-compatible bucket. Write a custom adapter only for storage that has no S3 API, such as Google Cloud Storage or a local disk.

## How the server picks a backend

For every request, the server uses the first backend in this list that is configured:

1. The adapter that `src/custom-adapter.ts` returns, when it returns one.
2. The `KV_STORE` binding.
3. The `R2_STORE` binding.
4. The `S3_*` variables, when `S3_BUCKET` is set.

A binding wins over the `S3_*` variables. To use S3 on Cloudflare Workers, remove the `r2_buckets` entry from `apps/api/wrangler.jsonc`.

With no backend, every cache request fails with a `500` error, and the server logs the reason:

```text
Invalid server configuration: no artifact storage. Bind KV_STORE or R2_STORE on Cloudflare, set S3_BUCKET and S3_ENDPOINT, or return an adapter from src/custom-adapter.ts.
```

The response body doesn't include the reason, so check the platform's logs.

## Switch to another backend

The server reads artifacts only from the backend it picks, so a new backend starts empty. Each task misses once and uploads a fresh artifact. The old backend keeps its artifacts until you delete them.
