Skip to content

Runtime Adapters

CruzJS is provider-agnostic. While Cloudflare Workers/Pages is the default target, you can deploy to AWS, Google Cloud, Azure, DigitalOcean, or self-hosted Docker using runtime adapters.

Each adapter implements the RuntimeAdapter interface, providing platform-specific implementations for database, cache, queue, AI, and storage bindings.

// server.cloudflare.ts — Cloudflare (default)
import { CloudflareAdapter } from '@cruzjs/adapter-cloudflare';
export default createCruzApp({
schema,
modules: [/* your modules */],
adapter: new CloudflareAdapter(),
pages: () => import('virtual:react-router/server-build'),
});
// server.ts — Docker / self-hosted
import { DockerAdapter } from '@cruzjs/adapter-docker';
export default createCruzApp({
schema,
modules: [/* your modules */],
adapter: new DockerAdapter(),
pages: () => import('virtual:react-router/server-build'),
});
PackageAdapterRuntime TypeUse Case
@cruzjs/adapter-cloudflareCloudflareAdapterEdgeCloudflare Workers/Pages
@cruzjs/adapter-awsAWSLambdaAdapterServerlessAWS Lambda + API Gateway
@cruzjs/adapter-awsAWSFargateAdapterContainerAWS ECS Fargate
@cruzjs/adapter-gcpGCPCloudRunAdapterContainerGoogle Cloud Run
@cruzjs/adapter-gcpGCPCloudFunctionsAdapterServerlessGoogle Cloud Functions
@cruzjs/adapter-azureAzureFunctionsAdapterServerlessAzure Functions
@cruzjs/adapter-azureAzureContainerAppsAdapterContainerAzure Container Apps
@cruzjs/adapter-digitaloceanDigitalOceanAppPlatformAdapterContainerDO App Platform
@cruzjs/adapter-dockerDockerAdapterContainerDocker, Dokploy, Coolify, K8s
  • Edge — Runs at the edge (Cloudflare Workers). Lowest latency, V8 isolate runtime.
  • Serverless — Scale-to-zero functions (Lambda, Cloud Functions). waitUntil() must be flushed before response returns.
  • Container — Long-running processes (Fargate, Cloud Run, Docker). waitUntil() is fire-and-forget.

All adapters implement this interface:

interface RuntimeAdapter {
readonly name: string;
readonly type: 'edge' | 'serverless' | 'container';
init(context: unknown): Promise<void>;
getDatabase(): unknown;
getCache(namespace?: string): CacheBinding;
getQueue<T>(name: string): QueueBinding<T>;
getLocalQueue<T>(name: string): LocalQueueLike<T> | null;
getAI(): AIBinding | null;
getBinding<T>(name: string): T | null;
getStorageBucket(): unknown | null;
waitUntil(promise: Promise<unknown>): void;
get env(): Record<string, string | undefined>;
get diagnostics(): Record<string, unknown>;
clear(): void;
}

Redis-like cache API with TTL support, key namespacing, and atomic counters.

interface CacheBinding {
get<T>(key: string): Promise<T | null>;
set(key: string, value: string | number | object, ttlSeconds?: number): Promise<boolean>;
delete(key: string): Promise<boolean>;
exists(key: string): Promise<boolean>;
keys(pattern: string): Promise<string[]>;
clear(): Promise<number>;
increment(key: string, by?: number): Promise<number>;
decrement(key: string, by?: number): Promise<number>;
}

Message dispatch for background job processing.

interface QueueBinding<T = unknown> {
send(message: T): Promise<void>;
sendBatch(messages: { body: T }[]): Promise<void>;
}

Provider-agnostic AI operations for chat, embeddings, and structured extraction.

interface AIBinding {
chat(options: AIChatOptions): Promise<string | null>;
embed(texts: string[], model?: string): Promise<number[][] | null>;
describeImage(image: ArrayBuffer, prompt?: string): Promise<string | null>;
analyzeSentiment(text: string): Promise<AISentimentResult | null>;
extractStructured<T>(options: AIExtractOptions<T>): Promise<T | null>;
}

Beyond the core bindings, the RuntimeAdapter interface exposes optional methods for advanced features. These return null when the adapter does not support them, and the corresponding modules fall back to in-memory or no-op implementations.

interface RuntimeAdapter {
// ... core methods above ...
// Optional bindings
getRateLimiter(): RateLimitAdapter | null;
getScheduler(): SchedulerAdapter | null;
getBroadcast(): BroadcastAdapter | null;
getSSEBackend(): SSEBackend | null;
getSearch(): SearchAdapter | null;
getSessionAdapter(): SessionAdapter | null;
getLogger(): LogAdapterBinding | null;
}
MethodReturnsPurpose
getRateLimiter()RateLimitAdapterDistributed rate limiting
getScheduler()SchedulerAdapterDistributed lock for scheduled tasks
getBroadcast()BroadcastAdapterPresence tracking for real-time channels
getSSEBackend()SSEBackendServer-Sent Events message delivery
getSearch()SearchAdapterFull-text search indexing and querying
getSessionAdapter()SessionAdapterSession storage and management
getLogger()LogAdapterBindingStructured logging
BindingCloudflareAWS LambdaAWS FargateGCP Cloud RunGCP FunctionsAzure FunctionsAzure ContainersDigitalOceanDocker
DatabaseD1DynamoDB / RDSRDSCloud SQLCloud SQLCosmos DBCosmos DBManaged DBPostgreSQL
CacheKVElastiCacheElastiCacheMemorystoreMemorystoreRedis CacheRedis CacheRedisRedis
QueueQueuesSQSSQSPub/SubPub/SubService BusService BusBullMQ
AIWorkers AIBedrockBedrockVertex AIVertex AIOpenAIOpenAIOllama
StorageR2S3S3GCSGCSBlob StorageBlob StorageSpacesLocal/S3
Rate LimiterKVElastiCacheElastiCacheMemorystoreMemorystoreRedis CacheRedis CacheRedisRedis
SchedulerKVDynamoDBRedisMemorystoreMemorystoreRedis CacheRedis CacheRedisRedis
BroadcastKVElastiCacheElastiCacheMemorystoreMemorystoreRedis CacheRedis CacheRedisRedis
SSE BackendKVRedisRedisRedisRedisRedis
SearchFTS5 (D1)OpenSearchOpenSearchOpenSearch
SessionsKVDynamoDBRedisMemorystoreMemorystoreRedis CacheRedis CacheRedisRedis
LoggerConsole/LogpushCloudWatchCloudWatchCloud LoggingCloud LoggingApp InsightsApp Insightsstdout

The adapter field is optional in createCruzApp(). Without it, the framework uses CloudflareContext directly (existing behavior). When provided, the adapter is initialized alongside CloudflareContext, so all existing services continue to work unchanged.