Plexcord LogoPlexcord
API Reference

Data & Storage

Persist plugin data across Discord sessions using Plexcord's DataStore API. Key-value storage with TypeScript generics.

Data & Storage

Plexcord provides DataStore, an async key-value store that persists data across Discord restarts.

Import

import { DataStore } from "@api/DataStore";

Core Methods

DataStore.get<T>(key)

Retrieve a stored value. Returns undefined if the key doesn't exist.

async function loadData() {
    const value = await DataStore.get<string>("myPlugin_username");
    // value is string | undefined
    console.log(value ?? "No username saved");
}

DataStore.set(key, value)

Store a value. Overwrites any existing value for that key.

async function saveData() {
    await DataStore.set("myPlugin_username", "Alice");
    await DataStore.set("myPlugin_count", 42);
    await DataStore.set("myPlugin_list", ["a", "b", "c"]);
}

DataStore.update<T>(key, updater)

Atomically update a value in-place. The updater receives the current value (or undefined) and returns the new value.

// Increment a counter safely
await DataStore.update<number>("myPlugin_visitCount", (current = 0) => current + 1);

// Add to a list safely
await DataStore.update<string[]>("myPlugin_log", (list = []) => {
    return [...list, `Entry at ${new Date().toISOString()}`];
});

DataStore.del(key)

Delete a stored value.

await DataStore.del("myPlugin_username");

DataStore.keys()

Get all keys (across all plugins). Filter by your prefix:

const allKeys = await DataStore.keys();
const myKeys = allKeys.filter(k => k.startsWith("myPlugin_"));

DataStore.getMany<T>(keys)

Get multiple values at once:

const [username, count] = await DataStore.getMany([
    "myPlugin_username",
    "myPlugin_count"
]) as [string | undefined, number | undefined];

DataStore.setMany(entries)

Set multiple values at once:

await DataStore.setMany([
    ["myPlugin_username", "Bob"],
    ["myPlugin_count", 0],
    ["myPlugin_lastSeen", Date.now()]
]);

Naming Keys

Always prefix your keys with your plugin name to avoid collisions:

// ✅ Good
DataStore.set("KeywordAlert_watchedWords", [...]);
DataStore.set("VoiceLogger_log", [...]);

// ❌ Bad: may collide with other plugins
DataStore.set("watchedWords", [...]);
DataStore.set("log", [...]);

Data Types

DataStore uses localforage internally and can store:

  • Primitives: string, number, boolean, null
  • Complex: plain objects, arrays
  • Not supported: class instances, functions, undefined (use null instead)
// ✅ Supported
await DataStore.set("key", { name: "Alice", count: 5 });
await DataStore.set("key", [1, 2, 3]);
await DataStore.set("key", "text");

// ❌ Not supported
await DataStore.set("key", new Map());  // Map → {}
await DataStore.set("key", undefined);  // Use null

Complete Example: Persistent Message Log

import definePlugin from "@utils/types";
import { DataStore } from "@api/DataStore";
import { Logger } from "@utils/Logger";

const logger = new Logger("MessageLog", "#4A90D9");
const STORAGE_KEY = "MessageLog_entries";
const MAX_ENTRIES = 100;

interface LogEntry {
    content: string;
    authorId: string;
    channelId: string;
    timestamp: number;
}

export default definePlugin({
    name: "MessageLog",
    description: "Persists a log of recent messages",
    authors: [{ name: "You", id: 0n }],

    async start() {
        const existing = await DataStore.get<LogEntry[]>(STORAGE_KEY);
        logger.info(`Loaded ${existing?.length ?? 0} existing log entries`);
    },

    flux: {
        async MESSAGE_CREATE({ message, channelId }) {
            if (message.author.bot) return;

            const entry: LogEntry = {
                content: message.content,
                authorId: message.author.id,
                channelId,
                timestamp: Date.now()
            };

            await DataStore.update<LogEntry[]>(STORAGE_KEY, (log = []) => {
                const updated = [...log, entry];
                // Keep only last 100 entries
                return updated.slice(-MAX_ENTRIES);
            });
        }
    },

    stop() {
        logger.info("Plugin stopped. Log preserved in storage.");
    }
});

Next Steps

On this page