🍡 mochi

SSR framework for Svelte 5 + Bun with islands-based selective hydration

On this page

Persistence

A few Mochi features keep server-side state that outlives a single request — queued jobs, cached values, rate-limit counters, spent captcha nonces. Each one defaults to in-memory storage and can be pointed at something durable instead.

FeatureMemorySQLitePostgresFile
Queues supported , default supported supported not supported
Cache supported , default planned planned supported
Image cache supported not supported not supported supported , default
Rate limiting supported , default supported supported not supported
Captcha nonces supported , default supported not supported not supported

default backend planned, not available yet

Built-in backends only — most features also accept a store you write yourself. In-memory state is per process, so it gives no shared view across a multi-instance deploy.

Per feature

  • Queues — in-memory by default. Point the serve-level queueStorage (or a descriptor’s storage) at a SQLite file ({ sqlite: path }), a Postgres database ({ postgres: url }), or an embedded PGlite instance ({ pglite }). One store serves every queue; Postgres storage is shared, so multiple processes can work one backlog.
  • Cachenew MochiCache({ storage }). Defaults to MemoryStorage; FileStorage writes one JSON file per entry. Built-in SQLite and Postgres backends are planned; until then any other backend is a Storage implementation (getItem / setItem / removeItem / clear), with serialize / deserialize when the backend needs strings.
  • Image cache — the one feature that persists by default: FileStorage under cacheDir. Pass image: { storage } to swap it (e.g. new MemoryStorage()); cacheDir is then ignored.
  • Rate limitingrateLimit: { store }. memoryStore() (default), sqliteStore({ path }) and postgresStore({ url }) all ship with the framework; MochiRateLimitStore is the interface for your own. Create the store once and share the instance across routes.
  • Captchacaptcha: { store: 'memory' | 'sqlite' }, plus storePath for the SQLite file. A custom NonceStore needs only consume(nonce, expiresAt).

Choosing a backend

BackendSurvives restartShared across instancesUse it when
In-memoryNoNoDevelopment, single-process apps, state that’s cheap to rebuild
FileYesOnly on shared storageCaches whose entries are large blobs (images, API responses)
SQLiteYesOnly on shared storageOne host, one process — durability without another service
PostgresYesYesSeveral instances behind a load balancer