Skip to content

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 KvRepository layered 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
deno add jsr:@fedify/denokv

SQLite

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/sqlite
npm add @fedify/sqlite
pnpm add @fedify/sqlite
yarn add @fedify/sqlite

Redis 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/redis
npm add @fedify/redis
pnpm add @fedify/redis
yarn add @fedify/redis

PostgreSQL

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/postgres
npm add @fedify/postgres
pnpm add @fedify/postgres
yarn add @fedify/postgres

Message 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
deno add jsr:@fedify/denokv

Redis 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/redis
npm add @fedify/redis
pnpm add @fedify/redis
yarn add @fedify/redis

PostgreSQL

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/postgres
npm add @fedify/postgres
pnpm add @fedify/postgres
yarn add @fedify/postgres

Repositories

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 botkit by 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-sqlite
npm add @fedify/botkit-sqlite
pnpm add @fedify/botkit-sqlite
yarn add @fedify/botkit-sqlite