Storage
Key-value storage for cache, sessions, files — Redis, Cloudflare KV, S3, and 30+ backends via unstorage.
Silgi includes unstorage — a universal key-value storage layer with 30+ drivers. Configure storage once, use it everywhere: caching, sessions, file uploads, feature flags, queues.
Setup
Mount drivers by path prefix. Each prefix routes to a different backend:
import { } from 'silgi'
import from 'unstorage/drivers/redis'
import from 'unstorage/drivers/memory'
import from 'unstorage/drivers/s3'
const = ({
: () => ({ }),
: {
: ({ : 'redis://localhost:6379' }),
: (),
: ({
: 'uploads',
: 'eu-west-1',
: ..!,
: ..!,
}),
},
})Keys are routed by prefix:
storage.setItem('cache:users', data) → Redis
storage.setItem('sessions:abc123', token) → Memory
storage.setItem('files:avatar.png', buf) → S3Using in procedures
Access storage via s.useStorage():
const = s.$input(z.object({ : z.string() })).$resolve(async ({ }) => {
const = s.useStorage('sessions')
const = await .getItem(.token)
if (!) return { : false }
return { : true, : }
})
const = s.$input(z.object({ : z.string(), : z.string() })).$resolve(async ({ }) => {
const = s.useStorage('files')
await .setItem(.name, .data)
return { : true }
})Cache integration
When you configure a cache mount, cacheQuery() uses it automatically — no setCacheStorage() needed:
import { } from 'silgi/cache'
const = silgi({
: () => ({ }),
: {
: redisDriver({ : 'redis://localhost' }),
},
})
// cacheQuery automatically uses the 'cache' mount → Redis
const = .$use(({ : 60 })).$resolve(({ }) => .db.users.findMany())Without a cache mount, cacheQuery() falls back to in-memory (default).
Analytics integration
When you configure a data mount, analytics automatically persists request and error entries to it. Data survives restarts and is pruned by retentionDays:
import from 'unstorage/drivers/fs'
const = silgi({
: () => ({}),
: {
: ({ : '.data' }),
},
})
.serve(appRouter, {
: { : 90 },
})Without a data mount, analytics falls back to in-memory (default).
Available drivers
All unstorage drivers work. Import from unstorage/drivers/*:
| Driver | Import | Use case |
|---|---|---|
| Memory | unstorage/drivers/memory | Development, testing, sessions |
| Redis | unstorage/drivers/redis | Cache, sessions, pub/sub |
| Filesystem | unstorage/drivers/fs | Config files, local storage |
| S3 | unstorage/drivers/s3 | File uploads, media |
| Cloudflare KV | unstorage/drivers/cloudflare-kv-binding | Edge cache, config |
| Vercel KV | unstorage/drivers/vercel | Serverless cache |
| MongoDB | unstorage/drivers/mongodb | Document storage |
| LRU Cache | unstorage/drivers/lru-cache | In-memory with eviction |
| HTTP | unstorage/drivers/http | Remote storage proxy |
| Overlay | unstorage/drivers/overlay | Multi-tier (L1 memory → L2 Redis) |
Multi-tier cache (overlay)
Layer memory in front of Redis for the fastest reads:
import from 'unstorage/drivers/overlay'
import from 'unstorage/drivers/memory'
import from 'unstorage/drivers/redis'
const = silgi({
: () => ({}),
: {
: ({
: [(), ({ : 'redis://localhost' })],
}),
},
})Read: checks memory first, then Redis. Write: writes to both. Best of both worlds.
Pre-built storage instance
If you need full control, pass a pre-built unstorage instance:
import { } from 'silgi/unstorage'
import from 'unstorage/drivers/redis'
const = ({})
.('cache', ({ : 'redis://localhost' }))
.('data', ({ : 'redis://localhost', : 'app' }))
const = silgi({
: () => ({}),
,
})API reference
const = s.useStorage('cache')
await .getItem('key') // Get value
await .setItem('key', value) // Set value
await .removeItem('key') // Delete
await .hasItem('key') // Check existence
await .getKeys() // List all keys
await .clear() // Delete allStorage credentials (Redis URL, S3 keys) stay in the config — they never leak to procedures, context, or client responses. Only the key-value API is exposed.