Redis, libSQL, and Turso Adapters
Purpose and Scope
This page helps Node-target Flue application authors choose and wire lightweight persistence adapters for Redis, Valkey, libSQL, and Turso. In Flue, persistence is not general application storage. It is the durable runtime backing for agent conversations, immutable attachments, accepted submissions, workflow runs, leases, claims, and event streams. Your customer records, tickets, payments, and other domain data remain owned by your application tables or services. The adapter is discovered from a source-root database module during the Node build, then the generated server runs startup migration or verification before handling durable work.
Sources: apps/docs/src/content/docs/ecosystem/databases/redis.md, apps/docs/src/content/docs/ecosystem/databases/libsql.md, apps/docs/src/content/docs/ecosystem/databases/turso.md, apps/docs/src/content/docs/ecosystem/databases/valkey.md
The shared boundary is a default-exported adapter in a source-root database file. Redis and Valkey use the Redis-protocol adapter package, while libSQL, embedded replicas, self-hosted libSQL servers, local SQLite files, and hosted Turso use the libSQL adapter package. These packages are intentionally driver-light at the Flue layer. You create and configure the provider client, then pass a small runner object to Flue. This keeps deployment-specific concerns, secrets, sync settings, snapshot policies, and managed-provider limitations outside the framework while preserving a stable persistence contract.
Sources: packages/redis/README.md, packages/libsql/README.md
Relevant Source Files
- apps/docs/src/content/docs/ecosystem/databases/redis.md — First-party Redis database guide with the blueprint command, environment variable, Node-only target note, inspection behavior, and durability guidance.
- apps/docs/src/content/docs/ecosystem/databases/libsql.md — First-party libSQL guide covering local files, self-hosted servers, embedded replicas, the generated runner shape, and environment loading.
- apps/docs/src/content/docs/ecosystem/databases/turso.md — First-party Turso guide showing that Turso uses the same libSQL adapter with hosted database URL and auth token configuration.
- apps/docs/src/content/docs/ecosystem/databases/valkey.md — First-party Valkey guide documenting Redis-protocol usage, Valkey-specific connection naming, and standalone or single-shard requirements.
- packages/redis/README.md — Package-level Redis and Valkey contract, deployment requirements, key isolation guidance, and storage-model description.
- packages/redis/src/redis-adapter.ts — Redis adapter implementation entry point importing the runtime persistence contracts, schema checks, leases, submissions, runs, event streams, and Redis store helpers.
- packages/libsql/README.md — Package-level libSQL and Turso contract, example runner, persisted state list, connection targets, and driver ownership model.
- packages/libsql/src/libsql-adapter.ts — libSQL adapter implementation entry point defining the public runner types and describing the SQLite-dialect persistence adapter contract.
Adapter Selection
Choose Redis or Valkey when you already operate a persistent standalone or managed single-shard Redis-protocol deployment and want shared state backed by commands, Lua scripts, hashes, sets, and sorted sets. The Redis blueprint uses the official node Redis client with a required connection URL. The Valkey blueprint is equivalent at the adapter level, but names the secret for Valkey and documents that support is specific to Valkey’s Redis protocol compatibility rather than every cache marketed as Redis-compatible. Both require durable deployment settings; cache-only deployments are explicitly outside the supported durability model.
Sources: apps/docs/src/content/docs/ecosystem/databases/redis.md, apps/docs/src/content/docs/ecosystem/databases/valkey.md, packages/redis/README.md
Choose libSQL when you want a local SQLite file, a self-hosted libSQL server, or an embedded replica. Choose Turso when you want hosted replicated libSQL. Turso is not a different Flue persistence implementation; it is the same libSQL adapter pointed at a hosted Turso database with an auth token. For local development, the libSQL guide emphasizes that the client reads environment values at runtime, so development commands can load an environment file while production should supply secrets from the hosting platform. Embedded replicas need additional client sync configuration that belongs to your client setup.
Sources: apps/docs/src/content/docs/ecosystem/databases/libsql.md, apps/docs/src/content/docs/ecosystem/databases/turso.md, packages/libsql/README.md
Quickstart Commands and Environment
The blueprints are the intended entry point for existing projects. They install the relevant Flue package and provider client, create the source-root database module, and follow the project’s existing environment-documentation convention when available. Use the provider-specific command so generated variable names and examples match the backing service you intend to run. These adapters apply to Node deployments only. The Cloudflare target uses Durable Object SQLite automatically and rejects a source-root database adapter file, so do not add these database blueprints to a Cloudflare-target project.
flue add database redis
flue add database valkey
flue add database libsql
flue add database turso| Adapter choice | Package | Required runtime variables | Typical target |
|---|---|---|---|
| Redis | @flue/redis | REDIS_URL | Persistent standalone or managed single-shard Redis |
| Valkey | @flue/redis | VALKEY_URL | Persistent standalone or managed single-shard Valkey |
| libSQL | @flue/libsql | LIBSQL_URL | Local SQLite file or self-hosted libSQL server |
| Turso | @flue/libsql | TURSO_DATABASE_URL, TURSO_AUTH_TOKEN | Hosted replicated libSQL |
Sources: apps/docs/src/content/docs/ecosystem/databases/redis.md, apps/docs/src/content/docs/ecosystem/databases/libsql.md, apps/docs/src/content/docs/ecosystem/databases/turso.md, apps/docs/src/content/docs/ecosystem/databases/valkey.md
Redis and Valkey Runner Contract
The Redis adapter accepts a Redis-native runner with command execution, script evaluation, optional pipelining, and close behavior. The canonical generated module connects the official client, sends raw commands with stringified arguments, evaluates Lua with separate key and argument lists, batches pipeline operations with a multi object, rejects any Error result, and closes the client during shutdown. Flue then calls migration at startup, records the runtime schema version, and inspects the server when possible. Inspection verifies that cluster mode is disabled and eviction policy is noeviction; disabling inspection is reserved for managed providers that deny both inspection commands after you independently verify the requirements.
import { redis } from '@flue/redis';
import { createClient } from 'redis';
const client = createClient({ url: process.env.REDIS_URL });
await client.connect();
export default redis({
command: (command, args = []) => client.sendCommand([command, ...args.map(String)]),
eval: (script, keys, args = []) => client.eval(script, { keys, arguments: args.map(String) }),
close: () => client.close(),
});Sources: packages/redis/README.md, packages/redis/src/redis-adapter.ts
Operationally, Redis and Valkey need persistent storage settings that match your recovery objective. The docs call out AOF with an explicit fsync policy and durable snapshots as normal options, and they require maxmemory policy noeviction. The noeviction setting prevents silent eviction of runtime state, but it does not by itself make acknowledged writes survive server loss. The initial support model is standalone servers and managed single-shard endpoints, not Redis Cluster. Flue keys use base64url segments and span independent atomic operations rather than a cluster hash-slot schema, so cluster routing is not treated as compatible.
Sources: apps/docs/src/content/docs/ecosystem/databases/redis.md, apps/docs/src/content/docs/ecosystem/databases/valkey.md, packages/redis/README.md
libSQL and Turso Runner Contract
The libSQL adapter accepts a runner with query, transaction, and close functions. Queries use SQLite-dialect parameterized SQL with question-mark placeholders and positional parameters, and must resolve to rows represented as plain objects. Transactions must run the callback inside one write transaction on a single connection, commit on success, roll back on failure, and provide only a query-capable transaction object to the callback. The adapter does not nest transactions. This deliberately small seam lets tests use in-memory clients and production applications use local files, self-hosted servers, embedded replicas, or Turso without changing Flue’s storage code.
import { libsql } from '@flue/libsql';
import { createClient, type ResultSet } from '@libsql/client';
const client = createClient({ url: process.env.LIBSQL_URL! });
const toRows = (rs: ResultSet) =>
rs.rows.map((row) => Object.fromEntries(rs.columns.map((column) => [column, row[column]])));
export default libsql({
query: async (text, params = []) => toRows(await client.execute({ sql: text, args: params })),
transaction: async (fn) => {
const tx = await client.transaction('write');
try {
const result = await fn({
query: async (text, params = []) => toRows(await tx.execute({ sql: text, args: params })),
});
await tx.commit();
return result;
} catch (error) {
await tx.rollback();
throw error;
} finally {
tx.close();
}
},
close: () => client.close(),
});Sources: packages/libsql/README.md, packages/libsql/src/libsql-adapter.ts
For a local SQLite file, serialize operations in one process so overlapping writes do not contend unexpectedly. The package README demonstrates a promise tail that runs each query or transaction after the previous operation settles. Hosted Turso uses the same runner shape, but the client is configured with a database URL and auth token. A self-hosted libSQL server uses its server URL, while an embedded replica uses a local file URL plus sync URL and auth token. In every case, the Flue adapter remains the same; only the application-owned client configuration changes.
Sources: apps/docs/src/content/docs/ecosystem/databases/libsql.md, apps/docs/src/content/docs/ecosystem/databases/turso.md, packages/libsql/README.md
Runtime Storage Model and Edge Cases
Both adapter families implement the runtime persistence contract consumed by Flue’s durable execution system. The source imports and package READMEs identify storage for canonical append-only conversation streams, immutable external attachments, accepted direct prompts and dispatch submissions, workflow run records, event streams, run indexes, claims, and leases. Replay currently starts from the canonical stream, and compaction or replay acceleration is deferred. Sessions append for the instance lifetime and do not expose per-session deletion. Whole-instance stream or attachment deletion methods exist as lower-level primitives, not as ordinary public orchestration tools.
Sources: packages/redis/README.md, packages/libsql/README.md, packages/redis/src/redis-adapter.ts, packages/libsql/src/libsql-adapter.ts
Redis has a few extra operational edge cases because Lua scripts and memory pressure interact with durability. The package notes that Redis Lua does not roll back earlier commands if a later command fails, so scripts validate key types first and allocate index capacity before authoritative state where possible. Normal operations repair indexes from authoritative hashes, and noeviction substantially limits partial transitions. Even so, running out of memory during a multi-command script can require operational recovery, so production deployments should maintain enough headroom and avoid treating Redis or Valkey as an expendable cache.
Sources: packages/redis/README.md, packages/redis/src/redis-adapter.ts
Next Steps
After selecting an adapter, add the matching blueprint, commit the generated source-root database module, and configure secrets in the environment used by your Node runtime. For Redis or Valkey, verify standalone or single-shard topology, noeviction, key isolation, and persistent recovery settings before production. For libSQL or Turso, verify the client connection target, transaction behavior, and runtime secret loading. Then run the Node development or build flow so Flue can discover the adapter, run startup migration, and persist durable agent and workflow state.
Related pages: database-guide, cli-add, cli-build-3, durable-execution, data-persistence-api