Skip to content

Platform Bindings

Every Aerostack function receives six native bindings through its env parameter. These are not HTTP clients — they are in-process Cloudflare bindings with near-zero latency.

interface Env {
DB: Database // Database (SQL, SQLite-compatible)
CACHE: Cache // Cache (key-value with TTL)
QUEUE: Queue // Queue (background jobs)
AI: AI // AI — Multi-provider LLM
VECTORIZE: VectorSearch // Vector Search (semantic similarity)
STORAGE: Storage // Storage (object storage with CDN)
}

Aerostack’s edge database is SQL-based (SQLite-compatible). Full SQL support, automatic replication, and zero-latency access from your function.

// Single row
const user = await env.DB
.prepare('SELECT * FROM users WHERE id = ?')
.bind(userId)
.first()
// Multiple rows
const { results } = await env.DB
.prepare('SELECT * FROM users WHERE active = ? ORDER BY created_at DESC LIMIT ?')
.bind(1, 50)
.all()
// Insert with returning
const created = await env.DB
.prepare('INSERT INTO users (email, name) VALUES (?, ?) RETURNING *')
.bind(email, name)
.first()
// Update
const { meta } = await env.DB
.prepare('UPDATE users SET name = ? WHERE id = ?')
.bind(newName, userId)
.run()
console.log(`Rows changed: ${meta.changes}`)
// Delete
await env.DB.prepare('DELETE FROM sessions WHERE expires_at < ?').bind(Date.now()).run()

Execute multiple statements in a single round trip. All statements run in an implicit transaction — if any fails, they all roll back.

const results = await env.DB.batch([
env.DB.prepare('INSERT INTO orders (user_id, total) VALUES (?, ?)').bind(userId, total),
env.DB.prepare('UPDATE users SET order_count = order_count + 1 WHERE id = ?').bind(userId),
env.DB.prepare('INSERT INTO audit_log (action, user_id) VALUES (?, ?)').bind('order_created', userId),
])
interface User {
id: number
email: string
name: string
created_at: string
}
const user = await env.DB
.prepare('SELECT * FROM users WHERE id = ?')
.bind(userId)
.first<User>()
// user is User | null

When to use: Structured data, relational queries, transactions, anything that needs ACID guarantees.


Aerostack’s cache provides a globally distributed key-value store. Reads are fast everywhere (eventually consistent). Writes propagate globally within 60 seconds.

// String values
await env.CACHE.put('user:123:profile', JSON.stringify(profile))
const raw = await env.CACHE.get('user:123:profile')
const profile = raw ? JSON.parse(raw) : null
// Typed get — parses JSON automatically
const profile = await env.CACHE.get('user:123:profile', 'json')
// Delete
await env.CACHE.delete('user:123:profile')
// Check existence without reading the value
const meta = await env.CACHE.getWithMetadata('user:123:profile')
if (meta.value === null) {
// Key does not exist
}
// Expire after 1 hour (3600 seconds)
await env.CACHE.put('session:abc', tokenData, { expirationTtl: 3600 })
// Expire at a specific timestamp (Unix seconds)
const oneHourFromNow = Math.floor(Date.now() / 1000) + 3600
await env.CACHE.put('session:abc', tokenData, { expiration: oneHourFromNow })

Attach metadata to a key without increasing the value size:

await env.CACHE.put('report:daily', reportJson, {
expirationTtl: 86400,
metadata: { generatedAt: Date.now(), version: 3 }
})
const { value, metadata } = await env.CACHE.getWithMetadata('report:daily', 'json')
console.log(`Report version: ${metadata.version}`)
// List all keys with a prefix
const { keys } = await env.CACHE.list({ prefix: 'user:123:' })
for (const key of keys) {
console.log(key.name, key.expiration)
}

The most common caching strategy — check cache first, query DB on miss, populate cache:

async function getCachedUser(env: Env, userId: number) {
const cacheKey = `user:${userId}`
// 1. Try cache
const cached = await env.CACHE.get(cacheKey, 'json')
if (cached) return cached
// 2. Query DB
const user = await env.DB
.prepare('SELECT * FROM users WHERE id = ?')
.bind(userId)
.first()
if (!user) return null
// 3. Populate cache (5 min TTL)
await env.CACHE.put(cacheKey, JSON.stringify(user), { expirationTtl: 300 })
return user
}

When to use: Session tokens, computed results, rate limit counters, configuration, any read-heavy data that can tolerate eventual consistency.


Aerostack’s queue provides reliable, at-least-once message delivery. Send messages from your fetch() handler and process them asynchronously in a queue() handler.

export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Send a single message
await env.QUEUE.send({
type: 'send-email',
to: 'user@example.com',
subject: 'Welcome',
body: 'Thanks for signing up.'
})
// Send a batch of messages
await env.QUEUE.sendBatch([
{ body: { type: 'resize-image', key: 'uploads/photo1.jpg' } },
{ body: { type: 'resize-image', key: 'uploads/photo2.jpg' } },
{ body: { type: 'resize-image', key: 'uploads/photo3.jpg' } },
])
return Response.json({ queued: true })
}
}

Add a queue() handler to your function. Cloudflare delivers messages in batches:

export default {
async fetch(request: Request, env: Env): Promise<Response> {
// ... your HTTP handler
},
async queue(batch: MessageBatch, env: Env): Promise<void> {
for (const msg of batch.messages) {
try {
const job = msg.body as { type: string; [key: string]: unknown }
switch (job.type) {
case 'send-email':
await sendEmail(job.to as string, job.subject as string, job.body as string)
break
case 'resize-image':
await resizeImage(env, job.key as string)
break
default:
console.error(`Unknown job type: ${job.type}`)
}
msg.ack() // Remove from queue
} catch (err) {
msg.retry() // Re-queue for retry
}
}
}
}
// Delay delivery by 60 seconds
await env.QUEUE.send(
{ type: 'reminder', userId: 123 },
{ delaySeconds: 60 }
)

When to use: Email sending, image processing, webhook fan-out, any work that should not block the HTTP response.


Run LLM inference directly from your function. Supports multiple providers and models with a unified interface.

// Basic completion
const response = await env.AI.run('@cf/meta/llama-3.1-8b-instruct', {
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'Explain edge computing in one paragraph.' }
]
})
console.log(response.response)
// With parameters
const response = await env.AI.run('@cf/meta/llama-3.1-8b-instruct', {
messages: [{ role: 'user', content: 'Write a haiku about databases.' }],
max_tokens: 100,
temperature: 0.7
})
const stream = await env.AI.run('@cf/meta/llama-3.1-8b-instruct', {
messages: [{ role: 'user', content: 'Tell me a story.' }],
stream: true
})
return new Response(stream, {
headers: { 'Content-Type': 'text/event-stream' }
})

Generate vector embeddings for semantic search:

const embedding = await env.AI.run('@cf/baai/bge-base-en-v1.5', {
text: 'How do I deploy a function?'
})
// embedding.data[0] is a float array (768 dimensions for bge-base)
const imageBuffer = await env.STORAGE.get('photos/cat.jpg')
const result = await env.AI.run('@cf/microsoft/resnet-50', {
image: [...new Uint8Array(await imageBuffer.arrayBuffer())]
})
// result: [{ label: 'tabby cat', score: 0.95 }, ...]
// Summarize
const summary = await env.AI.run('@cf/facebook/bart-large-cnn', {
input_text: longArticle,
max_length: 200
})
// Classify sentiment
const sentiment = await env.AI.run('@cf/huggingface/distilbert-sst-2-int8', {
text: 'This product is amazing!'
})

When to use: Text generation, summarization, classification, embeddings, image analysis — any ML inference that should run close to your data.


Aerostack’s vector search provides native vector similarity search. Store embeddings and query them with sub-millisecond latency from your function.

// Generate embedding, then store it
const embedding = await env.AI.run('@cf/baai/bge-base-en-v1.5', {
text: 'Aerostack functions run on Cloudflare Workers'
})
await env.VECTORIZE.upsert([{
id: 'doc-123',
values: embedding.data[0],
metadata: {
title: 'Functions Overview',
category: 'docs',
source: 'knowledge-base'
}
}])
// Embed the query
const queryEmbedding = await env.AI.run('@cf/baai/bge-base-en-v1.5', {
text: 'How do I deploy edge functions?'
})
// Find the 5 most similar documents
const results = await env.VECTORIZE.query(queryEmbedding.data[0], {
topK: 5,
returnMetadata: 'all'
})
for (const match of results.matches) {
console.log(`${match.id} — score: ${match.score}, title: ${match.metadata?.title}`)
}
const results = await env.VECTORIZE.query(queryEmbedding.data[0], {
topK: 10,
returnMetadata: 'all',
filter: {
category: 'docs'
}
})
await env.VECTORIZE.deleteByIds(['doc-123', 'doc-456'])

When to use: Semantic search, RAG (retrieval-augmented generation), recommendation engines, duplicate detection, any similarity-based lookup.


Aerostack Storage provides S3-compatible object storage with zero egress fees. Store files, images, PDFs, or any binary data.

// Store a file from a request
const formData = await request.formData()
const file = formData.get('file') as File
await env.STORAGE.put(`uploads/${file.name}`, file.stream(), {
httpMetadata: { contentType: file.type }
})
// Store generated content
const report = JSON.stringify(analyticsData)
await env.STORAGE.put('reports/daily.json', report, {
httpMetadata: { contentType: 'application/json' }
})
const object = await env.STORAGE.get('uploads/photo.jpg')
if (!object) {
return new Response('Not found', { status: 404 })
}
return new Response(object.body, {
headers: {
'Content-Type': object.httpMetadata?.contentType || 'application/octet-stream',
'Content-Length': String(object.size)
}
})
// Single delete
await env.STORAGE.delete('uploads/old-file.pdf')
// Batch delete
await env.STORAGE.delete(['temp/a.txt', 'temp/b.txt', 'temp/c.txt'])
const listed = await env.STORAGE.list({ prefix: 'uploads/', limit: 100 })
for (const object of listed.objects) {
console.log(`${object.key} — ${object.size} bytes, uploaded ${object.uploaded}`)
}
// Pagination
if (listed.truncated) {
const nextPage = await env.STORAGE.list({
prefix: 'uploads/',
cursor: listed.cursor
})
}
// Create a multipart upload for large files
const upload = await env.STORAGE.createMultipartUpload('videos/large.mp4', {
httpMetadata: { contentType: 'video/mp4' }
})
// Upload parts
const part1 = await upload.uploadPart(1, chunk1)
const part2 = await upload.uploadPart(2, chunk2)
// Complete
await upload.complete([part1, part2])

When to use: File uploads, image storage, document processing, backups, serving static assets, any binary data.


BindingTypeAccessBest For
env.DBDatabaseenv.DB.prepare().bind().all()Structured data, transactions
env.CACHECacheenv.CACHE.get() / .put()Hot data, sessions, counters
env.QUEUEQueueenv.QUEUE.send()Background jobs, async work
env.AIAienv.AI.run(model, input)LLM, embeddings, classification
env.VECTORIZEVectorSearchenv.VECTORIZE.query()Semantic search, RAG
env.STORAGEStorageenv.STORAGE.put() / .get()Files, images, binary data