Extension Backend Selection
rill extensions (fs, kv) from rill-ext provide JSON/filesystem backends. Separate packages offer alternative storage backends. Scripts use the same API regardless of backend — hosts swap backends without changing script code.
Backend Selection Strategy
| Deployment | fs Backend | kv Backend | Rationale |
|---|---|---|---|
| Development | JSON (@rcrsr/rill-ext-fs) | JSON (@rcrsr/rill-ext-kv) | Zero configuration, file-based persistence |
| Single-server | Local files (@rcrsr/rill-ext-fs) | SQLite (@rcrsr/rill-ext-kv-sqlite) | Drop-in database file, concurrent safe |
| Multi-server | S3 (@rcrsr/rill-ext-fs-s3) | Redis (@rcrsr/rill-ext-kv-redis) | Shared state, distributed access |
| Cloud/serverless | S3 (@rcrsr/rill-ext-fs-s3) | Redis (@rcrsr/rill-ext-kv-redis) | Cross-server access, managed services |
API Contract Guarantee
All kv backends implement KvExtensionContract from @rcrsr/rill-ext-kv. All fs backends implement FsExtensionContract from @rcrsr/rill-ext-fs. Contract properties use ApplicationCallable from @rcrsr/rill. Scripts import no backend-specific types — the same script runs unchanged across JSON, SQLite, Redis, S3 backends.
# Works with ANY kv backend (JSON, SQLite, Redis)
kv.set("user", "name", "Alice")
kv.get("user", "name") # => "Alice"
# Works with ANY fs backend (local, S3)
fs.write("/data/file.txt", "content")
fs.read("/data/file.txt") # => "content"Mount Configuration Examples
Development: JSON-backed kv
import { createKvExtension } from '@rcrsr/rill-ext-kv';
import { createFsExtension } from '@rcrsr/rill-ext-fs';
const kv = createKvExtension({
mounts: {
user: { store: './data/user.json' },
cache: { store: './data/cache.json' }
}
});
const fs = createFsExtension({
mounts: {
data: { path: './data', mode: 'read-write' }
}
});
const ctx = createRuntimeContext({
variables: { kv: kv.value, fs: fs.value },
});Single-server: SQLite kv + Local fs
import { createSqliteKvExtension } from '@rcrsr/rill-ext-kv-sqlite';
import { createFsExtension } from '@rcrsr/rill-ext-fs';
const kv = createSqliteKvExtension({
mounts: {
user: {
mode: 'read-write',
database: './data/app.db',
table: 'user_state',
schema: {
name: { type: 'string', default: '' },
count: { type: 'number', default: 0 }
}
},
cache: {
mode: 'read-write',
database: './data/cache.db',
table: 'cache_entries'
}
}
});
const fs = createFsExtension({
mounts: {
data: { path: './data', mode: 'read-write' }
}
});
const ctx = createRuntimeContext({
variables: { kv: kv.value, fs: fs.value },
});Multi-server: Redis kv + S3 fs
import { createRedisKvExtension } from '@rcrsr/rill-ext-kv-redis';
import { createS3FsExtension } from '@rcrsr/rill-ext-fs-s3';
const kv = createRedisKvExtension({
url: 'redis://localhost:6379',
mounts: {
user: {
mode: 'read-write',
prefix: 'app:user:',
schema: {
name: { type: 'string', default: '' },
count: { type: 'number', default: 0 }
}
},
cache: {
mode: 'read-write',
prefix: 'app:cache:',
ttl: 3600 // 1 hour expiry
}
},
writePolicy: 'immediate'
});
const fs = createS3FsExtension({
mounts: {
data: {
mode: 'read-write',
region: 'us-east-1',
bucket: 'my-app-data',
prefix: 'documents/',
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
}
}
}
});
const ctx = createRuntimeContext({
variables: { kv: kv.value, fs: fs.value },
});Backend Package Imports
Install and import external backends as separate packages:
SQLite kv backend:
npm install @rcrsr/rill-ext-kv-sqliteimport { createSqliteKvExtension } from '@rcrsr/rill-ext-kv-sqlite';Redis kv backend:
npm install @rcrsr/rill-ext-kv-redisimport { createRedisKvExtension } from '@rcrsr/rill-ext-kv-redis';S3 fs backend:
npm install @rcrsr/rill-ext-fs-s3import { createS3FsExtension } from '@rcrsr/rill-ext-fs-s3';Swapping Backends Without Script Changes
Scripts reference mount names and functions, never backend-specific configuration:
// Development backend (JSON)
const devKv = createKvExtension({
mounts: { user: { store: './dev.json' } }
});
const devCtx = createRuntimeContext({
variables: { kv: devKv.value },
});
// Production backend (Redis)
const prodKv = createRedisKvExtension({
url: process.env.REDIS_URL,
mounts: { user: { mode: 'read-write', prefix: 'prod:user:' } }
});
const prodCtx = createRuntimeContext({
variables: { kv: prodKv.value },
});
// Same script works with both contexts
const script = `
kv.set("user", "name", "Alice")
kv.get("user", "name")
`;
const devResult = await execute(parse(script), devCtx); // Uses JSON
const prodResult = await execute(parse(script), prodCtx); // Uses Redis