Storage and message queue
A BotKit bot relies on three pieces of backing infrastructure, each configured through an option on createBot() or createInstance():
kv- A key–value store that Fedify uses for federation internals, such as the bot's cryptographic keys and caches of remote objects. This one is required.
queue- A message queue that processes incoming and outgoing activities in the background. It is optional during development but expected in production, where you don't want activity delivery to block HTTP responses.
repository- A store for the bot's own data: its posts, followers, followees, sent follow requests, and poll votes. It is optional and, when omitted, defaults to a
KvRepositorylayered on the same key–value store.
This guide covers the choices for each and recommends pairings for production. For the repository API in full, see the Repository concept chapter.
Key–value stores
Key–value stores are used to store persistent data for your bot, such as messages, followers, and followees. Usually you would want to pair a key–value store with the main database for your application.
BotKit supports the following key–value store implementations:
Deno KV (Deno Deploy)
Deno KV is the simplest option when running on Deno Deploy. It's built into the Deno runtime with no additional infrastructure needed, provides automatic replication on Deno Deploy, and supports ACID transactions. However, it's only available in Deno environments, has limited querying capabilities, and size limits per value (64KB on Deno Deploy).
import { DenoKvStore } from "@fedify/denokv";
const kv = await Deno.openKv();
const bot = createBot<void>({
username: "mybot",
kv: new DenoKvStore(kv),
// ... other configuration
});Since DenoKvStore is provided by Fedify, you need to install the @fedify/denokv package to use it:
deno add jsr:@fedify/denokvSQLite
SQLite is a good choice for local development and testing, as well as for small-scale production deployments. It's lightweight and easy to set up, provides ACID compliance and transaction support, making it excellent for development and testing environments. However, it's not suitable for high-concurrency production use and has limited scalability.
import { createBot } from "@fedify/botkit";
import { SqliteKvStore } from "@fedify/sqlite";
import { DatabaseSync } from "node:sqlite";
const sqlite = new DatabaseSync("bot-data.db");
const bot = createBot<void>({
username: "mybot",
kv: new SqliteKvStore(sqlite),
});You need to install the @fedify/sqlite package to use the SqliteKvStore:
deno add jsr:@fedify/sqlitenpm add @fedify/sqlitepnpm add @fedify/sqliteyarn add @fedify/sqliteRedis or Valkey
Redis (or its open source fork Valkey) is recommended for production deployments needing high performance. It offers excellent performance, clustering support, and wide hosting options, making it ideal for scalable production environments.
import { createBot } from "@fedify/botkit";
import { RedisKvStore } from "@fedify/redis";
import { Redis } from "ioredis";
const redis = new Redis({
host: Deno.env.get("REDIS_HOST"),
port: parseInt(Deno.env.get("REDIS_PORT") ?? "6379"),
password: Deno.env.get("REDIS_PASSWORD"),
tls: Deno.env.get("REDIS_TLS") === "true" ? {} : undefined,
});
const bot = createBot<void>({
username: "mybot",
kv: new RedisKvStore(redis),
});import { createBot } from "@fedify/botkit";
import { RedisKvStore } from "@fedify/redis";
import { Redis } from "ioredis";
const redis = new Redis({
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT ?? "6379"),
password: process.env.REDIS_PASSWORD,
tls: process.env.REDIS_TLS === "true" ? {} : undefined,
});
const bot = createBot<void>({
username: "mybot",
kv: new RedisKvStore(redis),
});You need to install the @fedify/redis package to use the RedisKvStore:
deno add jsr:@fedify/redisnpm add @fedify/redispnpm add @fedify/redisyarn add @fedify/redisPostgreSQL
PostgreSQL is suitable for deployments needing complex queries or transactions. It provides ACID compliance, complex query support, robust backup solutions, and a mature ecosystem, making it an excellent choice when you need advanced database features.
import { createBot } from "@fedify/botkit";
import { PostgresKvStore } from "@fedify/postgres";
import postgres from "postgres";
const sql = postgres(Deno.env.get("DATABASE_URL")!);
const bot = createBot<void>({
username: "mybot",
kv: new PostgresKvStore(sql),
});import { createBot } from "@fedify/botkit";
import { PostgresKvStore } from "@fedify/postgres";
import postgres from "postgres";
const sql = postgres(process.env.DATABASE_URL!);
const bot = createBot<void>({
username: "mybot",
kv: new PostgresKvStore(sql),
});You need to install the @fedify/postgres package to use the PostgresKvStore:
deno add jsr:@fedify/postgresnpm add @fedify/postgrespnpm add @fedify/postgresyarn add @fedify/postgresMessage queues
Message queues are used to handle background tasks, such as sending messages and processing incoming activities. Usually you would want to pair a message queue with a key–value store for a compact and complete backend solution.
Deno KV Queue
Built on top of Deno KV and available in Deno runtimes. It needs no additional infrastructure and pairs naturally with a DenoKvStore, though it has limited throughput compared to dedicated message queue solutions.
IMPORTANT
Deno KV queues work only with a local Deno KV database, such as on a self-hosted Deno process. The rebuilt Deno Deploy does not support KV queues, so use a dedicated queue (or none) there instead; see the Deno Deploy guide.
import { DenoKvMessageQueue } from "@fedify/denokv";
const kv = await Deno.openKv();
const bot = createBot<void>({
username: "mybot",
kv: new DenoKvStore(kv),
queue: new DenoKvMessageQueue(kv),
});Since DenoKvMessageQueue is provided by Fedify, you need to install the @fedify/denokv package to use it:
deno add jsr:@fedify/denokvRedis or Valkey
Recommended for production deployments, offering high performance, reliable message delivery, the ability to share infrastructure with your key–value store, and good monitoring tools.
import { createBot } from "@fedify/botkit";
import { RedisKvStore, RedisMessageQueue } from "@fedify/redis";
import { Redis } from "ioredis";
function getRedis(): Redis {
return new Redis({
host: Deno.env.get("REDIS_HOST"),
port: parseInt(Deno.env.get("REDIS_PORT") ?? "6379"),
password: Deno.env.get("REDIS_PASSWORD"),
tls: Deno.env.get("REDIS_TLS") === "true" ? {} : undefined,
});
}
const bot = createBot<void>({
username: "mybot",
kv: new RedisKvStore(getRedis()),
queue: new RedisMessageQueue(getRedis),
});import { createBot } from "@fedify/botkit";
import { RedisKvStore, RedisMessageQueue } from "@fedify/redis";
import { Redis } from "ioredis";
function getRedis(): Redis {
return new Redis({
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT ?? "6379"),
password: process.env.REDIS_PASSWORD,
tls: process.env.REDIS_TLS === "true" ? {} : undefined,
});
}
const bot = createBot<void>({
username: "mybot",
kv: new RedisKvStore(getRedis()),
queue: new RedisMessageQueue(getRedis),
});You need to install the @fedify/redis package to use the RedisMessageQueue:
deno add jsr:@fedify/redisnpm add @fedify/redispnpm add @fedify/redisyarn add @fedify/redisPostgreSQL
Suitable when already using PostgreSQL for storage. It provides ACID compliance, can share infrastructure with your key–value store, offers good long-term persistence, and supports transactions, making it ideal when you want to consolidate your backend infrastructure.
import { createBot } from "@fedify/botkit";
import { PostgresKvStore, PostgresMessageQueue } from "@fedify/postgres";
import postgres from "postgres";
const sql = postgres(Deno.env.get("DATABASE_URL")!);
const bot = createBot<void>({
username: "mybot",
kv: new PostgresKvStore(sql),
queue: new PostgresMessageQueue(sql),
});import { createBot } from "@fedify/botkit";
import { PostgresKvStore, PostgresMessageQueue } from "@fedify/postgres";
import postgres from "postgres";
const sql = postgres(process.env.DATABASE_URL!);
const bot = createBot<void>({
username: "mybot",
kv: new PostgresKvStore(sql),
queue: new PostgresMessageQueue(sql),
});You need to install the @fedify/postgres package to use the PostgresMessageQueue:
deno add jsr:@fedify/postgresnpm add @fedify/postgrespnpm add @fedify/postgresyarn add @fedify/postgresRepositories
The key–value store and message queue back Fedify's federation layer. BotKit keeps its own data, the bot's posts, followers, followees, sent follow requests, and poll votes, in a repository. When you omit the repository option, BotKit wraps your key–value store in a KvRepository, so the default persists exactly as durably as the kv backend you chose above. You only need to set repository explicitly when you want a different trade-off.
NOTE
Choosing a dedicated repository does not remove the need for a key–value store. Fedify still uses kv for federation internals, so it stays required whichever repository you run.
The Repository concept chapter documents every class and its options. For deployment, the practical question is which one to run:
KvRepository(default)- Stores everything through the key–value store you already configured. When that store is durable, such as Deno KV, Redis, or PostgreSQL, this needs no extra setup and is a sound production choice.
SqliteRepository- Keeps bot data in a local SQLite file with write-ahead logging. It suits a single-machine deployment where you would rather not run a separate database server. Provided by the @fedify/botkit-sqlite package.
PostgresRepository- Stores bot data in PostgreSQL tables under a dedicated schema (named
botkitby default). Reach for it when several bot processes share one persistent store, or when you already operate PostgreSQL. Provided by the @fedify/botkit-postgres package. RedisRepository- Stores bot data directly in Redis data structures. Like
PostgresRepository, it fits deployments that span several processes, and it is convenient when Redis is already part of your stack. Provided by the @fedify/botkit-redis package.
A fourth class, MemoryCachedRepository, wraps any of the above with an in-memory cache that trades memory for lower read latency. It changes performance, not durability.
For a single-machine bot, SQLite can cover both roles without an external service. Point the key–value store and the repository at separate files so they don't contend for the same database lock:
import { createBot } from "@fedify/botkit";
import { SqliteKvStore } from "@fedify/sqlite";
import { SqliteRepository } from "@fedify/botkit-sqlite";
import { DatabaseSync } from "node:sqlite";
const bot = createBot<void>({
username: "mybot",
kv: new SqliteKvStore(new DatabaseSync("federation.db")),
repository: new SqliteRepository({ path: "bot-data.db" }),
});Install the package for whichever repository you choose. For the SQLite example above:
deno add jsr:@fedify/botkit-sqlitenpm add @fedify/botkit-sqlitepnpm add @fedify/botkit-sqliteyarn add @fedify/botkit-sqlite