Persistent storage
Use KV for data your bot learns or changes while it runs: server settings, counters, warnings, user preferences, and other small JSON records.
KV data belongs to one deployment. It survives publishes, rollbacks, runtime restarts, and isolate recycling. Another deployment cannot read it.
Use project files for configuration shipped with a revision, and module variables for temporary caches that are safe to lose. KV is not a file store, event archive, or place for credentials.
Namespaces, keys, and values
A namespace groups one kind of data. A key identifies one record inside it:
guild-settings
├── 123456789012345678 → { "welcomeChannelId": "234567890123456789" }
└── 345678901234567890 → { "welcomeChannelId": "456789012345678901" }
Both records are in the guild-settings namespace, and each Discord server ID is its key.
Values can be strings, numbers, booleans, null, arrays, or plain objects containing those types. get() returns undefined when the key does not exist.
Store settings for each server
Create the namespace once at the top level of your script:
type GuildSettings = {
welcomeChannelId: string;
};
const guildSettings = new weeble.KVNamespace("guild-settings");
Write a server’s settings after validating them in a command:
async function setWelcomeChannel(guildId: string, channelId: string) {
await guildSettings.put(guildId, { welcomeChannelId: channelId });
}
Read the same record when an event arrives:
discord.on(discord.events.GUILD_MEMBER_ADD, async (member) => {
const settings = await guildSettings.get<GuildSettings>(member.guildId);
if (!settings) return;
const channel = await discord.fetchGuildTextChannel(
settings.welcomeChannelId,
);
if (channel) {
await channel.send(`Welcome ${member.toMention()}!`);
}
});
Publishing new code does not reset these settings. They remain until the key is deleted, its TTL expires, the namespace is cleared, or the deployment is deleted.
Expire temporary data
Set a TTL for values that should remove themselves. TTL is measured in milliseconds:
const cooldowns = new weeble.KVNamespace("cooldowns");
async function startCooldown(userId: string) {
await cooldowns.put(
`user:${userId}`,
true,
{ ttl: 10 * 60 * 1000 },
);
}
After ten minutes, cooldowns.get() returns undefined for that key.
Writing without ttl removes any previous expiry. Passing a TTL to increment() resets the counter’s expiry on every increment; omitting it preserves an existing expiry.
Inspect data in VS Code
Expand KV in the Weeble sidebar, then expand a namespace. Select a key to open its JSON value and optional TTL in an editor.
Saving the document writes the new value. Invalid JSON or metadata is rejected with an editor diagnostic. The context menu can create or delete keys and clear an entire namespace.
KV values can be inspected and edited without changing the deployed source.
Important
KV values are application data, not secret storage. Do not put bot tokens, API keys, webhook URLs, or other credentials in KV.
Limits and larger reads
One event can make up to 100 KV operations. getMany() accepts up to 100 keys, and batch() accepts up to 100 writes or deletes in one atomic operation.
Listings return 100 records by default. For a larger namespace, use listPage() or itemsPage() and pass the returned cursor into the next call. A page can contain at most 1,000 records.
Keys are returned in lexicographic order, and cursors should be treated as opaque.
See Limits for the other execution budgets and KVNamespace for the complete API.