Ein Discord bot SQLite-Setup ist für kleine und mittelgroße Bots eine mehr als ausreichende Datenbanklösung. Ohne einen separaten Datenbankserver aufzusetzen, hältst du all deine Daten in einer einzigen Datei und persistierst in Sekunden Dinge wie ein Level-System, eine Wirtschaft, Verwarnungs-Logs oder Einstellungen. In dieser Anleitung zeige ich Schritt für Schritt, wie du einem Node.js-Bot mit discord.js und better-sqlite3 eine lokale Datenbank hinzufügst: Tabellen anlegen und schnelle, sichere Abfragen schreiben.
Warum SQLite und warum better-sqlite3?
SQLite ist eine serverlose, dateibasierte relationale Datenbank. Für einen Bot bringt das mehrere Vorteile:
- Keine Einrichtung: du musst keinen separaten Dienst wie MySQL oder PostgreSQL betreiben. Die Datenbank ist eine einzige
.sqlite-Datei. - Portabilität: den Bot auf einen anderen VPS umzuziehen bedeutet nur, diese Datei zu kopieren.
- Geschwindigkeit: die Daten werden von der Festplatte im selben Prozess wie deine App gelesen. Es gibt keine Netzwerklatenz.
Auf der Node.js-Seite gibt es zwei beliebte Treiber: node:sqlite (das mit Node 22+ ausgelieferte eingebaute Modul) und better-sqlite3. Ich bevorzuge hier better-sqlite3, weil es eine synchrone API hat. Das mag verkehrt klingen, aber da SQLite-Aufrufe extrem schnell abgeschlossen sind, schreibst du direkten, lesbaren Code, ohne mit async/await-Ketten zu jonglieren. Es ist eine ausgereifte, gut getestete Bibliothek, die Prepared Statements effizient verwaltet.
Installation und Projektstruktur
Fügen wir zuerst die Abhängigkeiten hinzu. better-sqlite3 ist ein natives Modul, das bei der Installation kompiliert wird; du brauchst also Build-Werkzeuge auf deinem Rechner.
npm install discord.js better-sqlite3
Eine einfache, saubere Struktur könnte so aussehen:
my-bot/
index.js # Einstiegspunkt des Bots
db.js # Datenbankverbindung und Schema
data/
bot.sqlite # SQLite-Datei (wird automatisch erstellt)
.gitignore
Wichtig: füge data/bot.sqlite immer zu deiner .gitignore hinzu. Deine Datenbank sollte niemals in der Versionsverwaltung landen.
Die Verbindung öffnen und das Schema anlegen
Die Verbindung an einer Stelle zu öffnen und zu exportieren ist der sauberste Ansatz, damit jede Datei dieselbe Verbindung teilt. In db.js:
const Database = require('better-sqlite3');
const path = require('node:path');
const db = new Database(path.join(__dirname, 'data', 'bot.sqlite'));
// Empfohlene Einstellungen fuer Leistung und Robustheit
db.pragma('journal_mode = WAL');
db.pragma('foreign_keys = ON');
// Tabelle anlegen, falls sie nicht existiert (bei jedem Start sicher)
db.exec(`
CREATE TABLE IF NOT EXISTS users (
user_id TEXT PRIMARY KEY,
guild_id TEXT NOT NULL,
xp INTEGER NOT NULL DEFAULT 0,
level INTEGER NOT NULL DEFAULT 1,
coins INTEGER NOT NULL DEFAULT 0
);
`);
module.exports = db;
journal_mode = WAL (Write-Ahead Logging) ist für einen Bot fast immer die richtige Wahl, weil es gleichzeitiges Lesen und Schreiben deutlich besser handhabt. Dank CREATE TABLE IF NOT EXISTS kannst du die Tabelle bei jedem Bot-Start sicher vorbereiten.
Sicheres Lesen und Schreiben mit Prepared Statements
Der richtige Ansatz in better-sqlite3 ist die Verwendung von Prepared Statements. Sie sind schneller und schützen dich, da du Werte als Parameter übergibst, vor SQL-Injection. Bette niemals Benutzereingaben per String-Verkettung in eine Abfrage ein.
const db = require('./db');
// Abfragen einmal vorbereiten und wiederverwenden
const getUser = db.prepare(
'SELECT * FROM users WHERE user_id = ? AND guild_id = ?'
);
const upsertXp = db.prepare(`
INSERT INTO users (user_id, guild_id, xp)
VALUES (@userId, @guildId, @amount)
ON CONFLICT(user_id) DO UPDATE SET xp = xp + @amount
`);
function addXp(userId, guildId, amount) {
upsertXp.run({ userId, guildId, amount });
return getUser.get(userId, guildId);
}
Ein paar wichtige Punkte hier:
.get()gibt eine einzelne Zeile zurück,.all()gibt alle Zeilen als Array zurück, und.run()wird fürINSERT/UPDATE/DELETEverwendet.- Du kannst Positionsparameter mit
?oder benannte Parameter mit@namenutzen. ON CONFLICT ... DO UPDATE(ein „Upsert") fügt ein, wenn der Datensatz fehlt, und aktualisiert, wenn er existiert. Ideal für Level-Systeme.
Ein Nachrichten-Event mit der Datenbank verbinden
Verbinden wir das nun mit einem echten Event auf der discord.js-Seite. Vergib etwas XP, sobald ein Nutzer eine Nachricht sendet:
const { Client, GatewayIntentBits } = require('discord.js');
const { addXp } = require('./xp');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
});
client.on('messageCreate', (message) => {
if (message.author.bot || !message.guild) return;
const user = addXp(message.author.id, message.guild.id, 5);
// Einfache Level-Up-Pruefung
const needed = user.level * 100;
if (user.xp >= needed) {
db.prepare('UPDATE users SET level = level + 1 WHERE user_id = ?')
.run(message.author.id);
message.reply(`Glueckwunsch, Level ${user.level + 1}!`);
}
});
client.login(process.env.DISCORD_TOKEN);
Hinweis: MessageContent ist ein privilegierter Intent, und du musst ihn im Discord Developer Portal aktivieren, um auf den Nachrichteninhalt zuzugreifen.
Massenoperationen und Leistung
Viele Schreibvorgänge einzeln auszuführen greift zu oft auf die Festplatte zu. Sie in eine Transaction zu verpacken ist sowohl deutlich schneller als auch eine Alles-oder-nichts-Garantie:
const insertMany = db.transaction((rows) => {
for (const row of rows) upsertXp.run(row);
});
// Hunderte Zeilen in einem einzigen Festplattenvorgang
insertMany(grosseDatenListe);
Ein paar zusätzliche Tipps: öffne und schließe die Datenbank nicht wiederholt, nutze eine einzige Verbindung über die gesamte Lebensdauer der App; füge mit CREATE INDEX einen Index auf häufig abgefragte Spalten hinzu; und sichere deine bot.sqlite-Datei regelmäßig, denn all deine Daten liegen in dieser einen Datei.
Häufige Fragen
Reicht SQLite für einen großen Bot?
Für Bots, die aus einem einzigen Prozess heraus zugegriffen werden und bis zu zehntausende Nutzer bedienen, läuft SQLite problemlos. Für riesige Projekte mit vielen gleichzeitigen Schreibvorgängen oder wenn du den Bot horizontal über mehrere Prozesse oder Server skalieren musst, ist der Wechsel zu einer Serverdatenbank wie PostgreSQL sinnvoller.
better-sqlite3 ist synchron; blockiert es nicht den Bot?
SQLite-Abfragen dauern meist Mikrosekunden, daher blockieren sie in der Praxis die Event-Loop nicht spürbar. Bündele dennoch sehr große Massenoperationen innerhalb einer Transaction und vermeide es, Tausende Abfragen einzeln auszuführen.
Was passiert, wenn die Datenbankdatei beschädigt wird?
Der WAL-Modus verbessert die Robustheit gegen plötzliche Abschaltungen, doch regelmäßige Backups bleiben unerlässlich. Kopiere die Datei lieber nicht, während der Bot läuft; nutze die von better-sqlite3 angebotene Backup-Methode oder stoppe den Bot und kopiere die Datei.
Brauchst du eine solide Datenbankgrundlage für deinen Bot? Wenn du einen skalierbaren Discord-Bot für ein Level-System, eine Wirtschaft oder Moderations-Logs entwerfen willst, nimm Kontakt mit mir auf — lass uns gemeinsam die passende Lösung für dein Projekt bauen.