> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/cloudflare/vinext/llms.txt
> Use this file to discover all available pages before exploring further.

# Cloudflare Bindings

> Access KV, D1, R2, Durable Objects, and other Cloudflare bindings

# Cloudflare Bindings

Cloudflare Workers provide **bindings** to access platform resources like KV, D1, R2, Durable Objects, AI, and more. vinext applications can access these bindings directly in Server Components, Server Actions, Route Handlers, and middleware.

## Overview

Bindings are environment variables of special types provided by the Cloudflare Workers runtime. They're configured in `wrangler.jsonc` and accessed via the `env` parameter.

## Binding Types

### KV (Key-Value Store)

Globally distributed, eventually consistent key-value storage.

```jsonc filename="wrangler.jsonc" theme={null}
{
  "kv_namespaces": [
    { "binding": "MY_KV", "id": "abc123" }
  ]
}
```

```ts filename="worker/index.ts" theme={null}
interface Env {
  MY_KV: KVNamespace
}

export default {
  async fetch(request: Request, env: Env) {
    // Access KV
    await env.MY_KV.put('key', 'value')
    const value = await env.MY_KV.get('key')
    
    return handler.fetch(request)
  }
}
```

See [KV Cache Handler](/api/cloudflare/kv-cache-handler) for ISR integration.

### D1 (SQL Database)

Serverless SQL database built on SQLite.

```jsonc filename="wrangler.jsonc" theme={null}
{
  "d1_databases": [
    { "binding": "DB", "database_id": "xyz789" }
  ]
}
```

```ts filename="app/api/users/route.ts" theme={null}
import { getEnv } from 'vinext/cloudflare'

export async function GET() {
  const env = getEnv()
  const { results } = await env.DB.prepare('SELECT * FROM users').all()
  return Response.json(results)
}
```

### R2 (Object Storage)

S3-compatible object storage.

```jsonc filename="wrangler.jsonc" theme={null}
{
  "r2_buckets": [
    { "binding": "MY_BUCKET", "bucket_name": "my-bucket" }
  ]
}
```

```ts filename="app/actions.ts" theme={null}
'use server'

import { getEnv } from 'vinext/cloudflare'

export async function uploadFile(formData: FormData) {
  const env = getEnv()
  const file = formData.get('file') as File
  const buffer = await file.arrayBuffer()
  
  await env.MY_BUCKET.put(file.name, buffer, {
    httpMetadata: {
      contentType: file.type
    }
  })
}
```

### Durable Objects

Stateful serverless objects with strong consistency.

```jsonc filename="wrangler.jsonc" theme={null}
{
  "durable_objects": {
    "bindings": [
      { "name": "COUNTER", "class_name": "Counter" }
    ]
  }
}
```

```ts filename="app/api/counter/route.ts" theme={null}
import { getEnv } from 'vinext/cloudflare'

export async function GET() {
  const env = getEnv()
  const id = env.COUNTER.idFromName('global')
  const stub = env.COUNTER.get(id)
  const count = await stub.fetch('https://fake/increment').then(r => r.text())
  return Response.json({ count: parseInt(count) })
}
```

### AI (Workers AI)

Serverless GPU inference for LLMs and other AI models.

```jsonc filename="wrangler.jsonc" theme={null}
{
  "ai": {
    "binding": "AI"
  }
}
```

```ts filename="app/api/chat/route.ts" theme={null}
import { getEnv } from 'vinext/cloudflare'

export async function POST(request: Request) {
  const env = getEnv()
  const { messages } = await request.json()
  
  const response = await env.AI.run('@cf/meta/llama-3.1-8b-instruct', {
    messages
  })
  
  return Response.json(response)
}
```

### Vectorize (Vector Database)

Vector embeddings storage and similarity search.

```jsonc filename="wrangler.jsonc" theme={null}
{
  "vectorize": [
    { "binding": "VECTORIZE", "index_name": "my-index" }
  ]
}
```

```ts filename="app/api/search/route.ts" theme={null}
import { getEnv } from 'vinext/cloudflare'

export async function POST(request: Request) {
  const env = getEnv()
  const { query } = await request.json()
  
  // Generate embedding
  const { data } = await env.AI.run('@cf/baai/bge-base-en-v1.5', {
    text: query
  })
  
  // Search vectors
  const results = await env.VECTORIZE.query(data[0], { topK: 10 })
  return Response.json(results)
}
```

### Queues (Message Queue)

Asynchronous message queues.

```jsonc filename="wrangler.jsonc" theme={null}
{
  "queues": {
    "producers": [
      { "binding": "MY_QUEUE", "queue": "my-queue" }
    ]
  }
}
```

```ts filename="app/actions.ts" theme={null}
'use server'

import { getEnv } from 'vinext/cloudflare'

export async function sendEmail(to: string, subject: string, body: string) {
  const env = getEnv()
  await env.MY_QUEUE.send({ to, subject, body })
}
```

### Service Bindings

Call other Workers directly.

```jsonc filename="wrangler.jsonc" theme={null}
{
  "services": [
    { "binding": "AUTH_SERVICE", "service": "auth-worker" }
  ]
}
```

```ts filename="app/api/login/route.ts" theme={null}
import { getEnv } from 'vinext/cloudflare'

export async function POST(request: Request) {
  const env = getEnv()
  const { username, password } = await request.json()
  
  // Call auth worker
  const response = await env.AUTH_SERVICE.fetch('https://fake/verify', {
    method: 'POST',
    body: JSON.stringify({ username, password })
  })
  
  return response
}
```

### ASSETS (Static Assets)

Access static files from the Workers Assets binding.

```jsonc filename="wrangler.jsonc" theme={null}
{
  "assets": {
    "directory": "dist/client",
    "binding": "ASSETS"
  }
}
```

The ASSETS binding is used internally by vinext for static file serving and image optimization. You typically don't access it directly.

### IMAGES (Cloudflare Images)

On-the-fly image resizing and transcoding.

```jsonc filename="wrangler.jsonc" theme={null}
{
  "images": {
    "binding": "IMAGES"
  }
}
```

See [Image Optimization](/api/cloudflare/image-optimization) for usage.

## Accessing Bindings

### Worker Entry

Bindings are passed to your worker's `fetch` handler:

```ts filename="worker/index.ts" theme={null}
import handler from 'vinext/server/app-router-entry'

interface Env {
  MY_KV: KVNamespace
  DB: D1Database
  MY_BUCKET: R2Bucket
  AI: Ai
}

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    // Bindings are available in env
    const value = await env.MY_KV.get('key')
    
    return handler.fetch(request, env, ctx)
  }
}
```

### Server Components

Use `getEnv()` to access bindings in Server Components:

```tsx filename="app/posts/page.tsx" theme={null}
import { getEnv } from 'vinext/cloudflare'

export default async function Posts() {
  const env = getEnv()
  const { results } = await env.DB.prepare('SELECT * FROM posts').all()
  
  return (
    <div>
      {results.map((post: any) => (
        <article key={post.id}>{post.title}</article>
      ))}
    </div>
  )
}
```

### Server Actions

```ts filename="app/actions.ts" theme={null}
'use server'

import { getEnv } from 'vinext/cloudflare'

export async function createPost(formData: FormData) {
  const env = getEnv()
  const title = formData.get('title')
  const content = formData.get('content')
  
  await env.DB.prepare('INSERT INTO posts (title, content) VALUES (?, ?)')
    .bind(title, content)
    .run()
}
```

### Route Handlers

```ts filename="app/api/posts/route.ts" theme={null}
import { getEnv } from 'vinext/cloudflare'

export async function GET() {
  const env = getEnv()
  const { results } = await env.DB.prepare('SELECT * FROM posts').all()
  return Response.json(results)
}
```

### Middleware

```ts filename="middleware.ts" theme={null}
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { getEnv } from 'vinext/cloudflare'

export async function middleware(request: NextRequest) {
  const env = getEnv()
  const sessionId = request.cookies.get('session')?.value
  
  if (sessionId) {
    const session = await env.MY_KV.get(`session:${sessionId}`)
    if (session) {
      return NextResponse.next()
    }
  }
  
  return NextResponse.redirect(new URL('/login', request.url))
}
```

## Type Safety

Define your `Env` interface once and use it everywhere:

```ts filename="types/env.ts" theme={null}
export interface Env {
  // KV
  MY_KV: KVNamespace
  VINEXT_CACHE: KVNamespace
  
  // D1
  DB: D1Database
  
  // R2
  MY_BUCKET: R2Bucket
  
  // AI
  AI: Ai
  
  // Vectorize
  VECTORIZE: VectorizeIndex
  
  // Queues
  MY_QUEUE: Queue
  
  // Service bindings
  AUTH_SERVICE: Fetcher
  
  // Images
  IMAGES: any
  
  // Assets
  ASSETS: Fetcher
}
```

```ts filename="worker/index.ts" theme={null}
import type { Env } from '../types/env'
import handler from 'vinext/server/app-router-entry'

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext) {
    return handler.fetch(request, env, ctx)
  }
}
```

Now TypeScript enforces correct binding types throughout your app.

## getEnv() Implementation

The `getEnv()` helper uses AsyncLocalStorage to access bindings from anywhere in your app:

```ts theme={null}
import { getEnv } from 'vinext/cloudflare'

const env = getEnv() // Returns Env from current request context
```

If called outside a request context, it throws an error.

## Common Patterns

### Database Connection Pool

D1 doesn't require connection pooling (it's serverless), but you can create a helper:

```ts filename="lib/db.ts" theme={null}
import { getEnv } from 'vinext/cloudflare'

export function getDB() {
  return getEnv().DB
}
```

```tsx filename="app/posts/page.tsx" theme={null}
import { getDB } from '@/lib/db'

export default async function Posts() {
  const db = getDB()
  const { results } = await db.prepare('SELECT * FROM posts').all()
  return <div>{/* ... */}</div>
}
```

### Multi-Tenant KV

Use key prefixes for multi-tenant isolation:

```ts filename="lib/kv.ts" theme={null}
import { getEnv } from 'vinext/cloudflare'

export function getTenantKV(tenantId: string) {
  const kv = getEnv().MY_KV
  
  return {
    async get(key: string) {
      return kv.get(`${tenantId}:${key}`)
    },
    async put(key: string, value: string) {
      return kv.put(`${tenantId}:${key}`, value)
    },
    async delete(key: string) {
      return kv.delete(`${tenantId}:${key}`)
    }
  }
}
```

### Caching Wrapper

Wrap expensive operations with KV caching:

```ts filename="lib/cache.ts" theme={null}
import { getEnv } from 'vinext/cloudflare'

export async function cached<T>(
  key: string,
  fn: () => Promise<T>,
  ttl: number = 3600
): Promise<T> {
  const kv = getEnv().MY_KV
  
  // Try cache
  const cached = await kv.get(key, 'json')
  if (cached) return cached as T
  
  // Compute
  const result = await fn()
  
  // Store
  await kv.put(key, JSON.stringify(result), { expirationTtl: ttl })
  
  return result
}
```

```tsx filename="app/posts/page.tsx" theme={null}
import { cached } from '@/lib/cache'

export default async function Posts() {
  const posts = await cached('posts', async () => {
    const response = await fetch('https://api.example.com/posts')
    return response.json()
  }, 60)
  
  return <div>{/* ... */}</div>
}
```

## Development vs Production

### Local Development

Use `wrangler dev` to access bindings locally:

```bash theme={null}
wrangler dev
```

This starts a local Workers runtime with your configured bindings. D1 uses SQLite locally, KV uses in-memory storage.

### vinext dev

The `vinext dev` command runs Vite's dev server without Workers bindings. To test with bindings locally:

1. Build the app: `vinext build`
2. Run `wrangler dev`: `wrangler dev`

Or use the vinext deploy preview:

```bash theme={null}
vinext deploy --preview
```

## Examples

### Full-Stack D1 App

```tsx filename="app/todos/page.tsx" theme={null}
import { getEnv } from 'vinext/cloudflare'
import { revalidatePath } from 'next/cache'

export default async function Todos() {
  const env = getEnv()
  const { results: todos } = await env.DB.prepare('SELECT * FROM todos').all()
  
  async function createTodo(formData: FormData) {
    'use server'
    const env = getEnv()
    const title = formData.get('title')
    await env.DB.prepare('INSERT INTO todos (title) VALUES (?)').bind(title).run()
    revalidatePath('/todos')
  }
  
  return (
    <div>
      <form action={createTodo}>
        <input name="title" required />
        <button>Add</button>
      </form>
      <ul>
        {todos.map((todo: any) => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
    </div>
  )
}
```

### AI-Powered Search

```tsx filename="app/search/page.tsx" theme={null}
import { getEnv } from 'vinext/cloudflare'

export default async function Search({
  searchParams
}: {
  searchParams: Promise<{ q?: string }>
}) {
  const { q } = await searchParams
  if (!q) return <div>Enter a search query</div>
  
  const env = getEnv()
  
  // Generate embedding
  const { data } = await env.AI.run('@cf/baai/bge-base-en-v1.5', { text: q })
  
  // Search vectors
  const results = await env.VECTORIZE.query(data[0], { topK: 5 })
  
  return (
    <div>
      <h1>Results for "{q}"</h1>
      <ul>
        {results.matches.map((match: any) => (
          <li key={match.id}>{match.metadata.title}</li>
        ))}
      </ul>
    </div>
  )
}
```

## Related

* [KV Cache Handler](/api/cloudflare/kv-cache-handler) - Use KV for ISR caching
* [Image Optimization](/api/cloudflare/image-optimization) - Cloudflare Images integration
* [Deploying to Cloudflare](/deploy/cloudflare) - Deployment guide
* [Cloudflare Workers Docs](https://developers.cloudflare.com/workers/) - Official platform documentation
