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
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.
{
"kv_namespaces": [
{ "binding": "MY_KV", "id": "abc123" }
]
}
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 for ISR integration.
D1 (SQL Database)
Serverless SQL database built on SQLite.
{
"d1_databases": [
{ "binding": "DB", "database_id": "xyz789" }
]
}
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.
{
"r2_buckets": [
{ "binding": "MY_BUCKET", "bucket_name": "my-bucket" }
]
}
'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.
{
"durable_objects": {
"bindings": [
{ "name": "COUNTER", "class_name": "Counter" }
]
}
}
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.
{
"ai": {
"binding": "AI"
}
}
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.
{
"vectorize": [
{ "binding": "VECTORIZE", "index_name": "my-index" }
]
}
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.
{
"queues": {
"producers": [
{ "binding": "MY_QUEUE", "queue": "my-queue" }
]
}
}
'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.
{
"services": [
{ "binding": "AUTH_SERVICE", "service": "auth-worker" }
]
}
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.
{
"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.
{
"images": {
"binding": "IMAGES"
}
}
See Image Optimization for usage.
Accessing Bindings
Worker Entry
Bindings are passed to your worker’s fetch handler:
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:
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
'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
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
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:
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
}
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:
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:
import { getEnv } from 'vinext/cloudflare'
export function getDB() {
return getEnv().DB
}
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:
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:
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
}
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:
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:
- Build the app:
vinext build
- Run
wrangler dev: wrangler dev
Or use the vinext deploy preview:
Examples
Full-Stack D1 App
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
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>
)
}