# Cloudflare State Store

import { Tabs, TabItem, Steps } from '@astrojs/starlight/components';

CloudflareStateStore provides a [State Store](/concepts/state) using a Cloudflare Worker and a SQLite3 Durable Object.

<Steps>

1. **Generate a state token**

   Create a secure token for state store authentication:

   ```sh
   openssl rand -base64 32
   ```

   Copy the generated token - you'll need it in the next step.

2. **Set environment variables**

   Add the token to your environment:

   ```sh
   # .env
   ALCHEMY_STATE_TOKEN=your-generated-token-here
   ```

   :::tip
   Store this token securely and don't commit it to version control.
   :::

   :::warning
   This token must be the same for all deployments on your Cloudflare account.
   :::

3. **Configure CloudflareStateStore**

   Update your `alchemy.run.ts` to use cloud state storage:

   ```typescript
   import alchemy from "alchemy";
   import { CloudflareStateStore } from "alchemy/state";

   const app = await alchemy("my-app", {
     stateStore: (scope) => new CloudflareStateStore(scope)
   });

   // Your resources here...

   await app.finalize();
   ```

4. **Deploy your app**

   Use the Alchemy CLI to deploy and create the state store worker:

   <Tabs syncKey="pkgManager">
     <TabItem label="bun">
       ```sh
       bun alchemy deploy
       ```
     </TabItem>
     <TabItem label="npm">
       ```sh
       npx alchemy deploy
       ```
     </TabItem>
     <TabItem label="pnpm">
       ```sh
       pnpm alchemy deploy
       ```
     </TabItem>
     <TabItem label="yarn">
       ```sh
       yarn alchemy deploy
       ```
     </TabItem>
   </Tabs>

   Alchemy automatically creates an `alchemy-state-service` worker in your Cloudflare account.

5. **Verify the state store**

   Check your Cloudflare dashboard to see the deployed worker:

   ```
   https://dash.cloudflare.com/workers
   ```

   You should see an `alchemy-state-service` worker handling your application state.

</Steps>

## Customization

### Custom Worker Name

Change the worker name to avoid conflicts or organize by environment:

```typescript
const app = await alchemy("my-app", {
  stateStore: (scope) => new CloudflareStateStore(scope, {
    scriptName: "my-app-state-prod"
  })
});
```

### Custom Token

Override the environment variable token:

```typescript
const app = await alchemy("my-app", {
  stateStore: (scope) => new CloudflareStateStore(scope, {
    stateToken: alchemy.secret(process.env.CUSTOM_STATE_TOKEN)
  })
});
```

### Force Worker Recreation

Force the worker to be recreated even if it exists:

```typescript
const app = await alchemy("my-app", {
  stateStore: (scope) => new CloudflareStateStore(scope, {
    forceUpdate: true
  })
});
```

## Environment-Specific Configuration

### Development

Use local filesystem for development, cloud for production:

```typescript
const app = await alchemy("my-app", {
  stateStore: process.env.NODE_ENV === "production" 
    ? (scope) => new CloudflareStateStore(scope)
    : undefined // Uses default FileSystemStateStore
});
```

### Per-Environment Workers

Use different workers for different environments:

```typescript
const stage = process.env.STAGE ?? "dev";

const app = await alchemy("my-app", {
  stage,
  stateStore: (scope) => new CloudflareStateStore(scope, {
    scriptName: `my-app-state-${stage}`
  })
});
```

## Authentication Requirements

CloudflareStateStore requires Cloudflare authentication. See the [Cloudflare Auth Guide](/guides/cloudflare) for setup options:

- **API Token** (recommended)
- **OAuth** via `wrangler login` 
- **Global API Key** (legacy)

:::tip
The same Cloudflare credentials used for other resources work with CloudflareStateStore.
:::

## How It Works

1. **Worker Creation**: CloudflareStateStore automatically deploys a Cloudflare Worker with Durable Objects
2. **State Storage**: Your application state is stored in Durable Objects for high performance
3. **Authentication**: All requests use your generated token for secure access
4. **Automatic Management**: The worker handles state operations (get, set, delete, list)

The generated worker appears in your Cloudflare dashboard and can be managed like any other worker.