Updated 25 October 2026
A bot gets really useful when it remembers things (points, settings, warnings) and gives users buttons to click. This guide builds a small working example with a SQLite database and a button, in JavaScript (discord.js) and in Python (discord.py). SQLite is a database in a single file: no separate database server needed.
What the example does
The command /button shows a button. Every click is counted per user in the database, and the bot replies with the user's total. The count survives restarts because it's stored in the file data.db.
JavaScript (discord.js)
package.json needs these packages (they are installed automatically when your bot starts):
{
"dependencies": {
"discord.js": "^14.16.0",
"better-sqlite3": "^11.0.0",
"dotenv": "^16.4.0"
}
}
index.js:
require('dotenv').config();
const { Client, GatewayIntentBits, Events, ActionRowBuilder, ButtonBuilder, ButtonStyle, MessageFlags } = require('discord.js');
const Database = require('better-sqlite3');
const db = new Database('data.db');
db.prepare('CREATE TABLE IF NOT EXISTS clicks (user_id TEXT PRIMARY KEY, count INTEGER NOT NULL DEFAULT 0)').run();
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
client.once(Events.ClientReady, async (c) => {
await c.application.commands.create({ name: 'button', description: 'Show a button' });
console.log(`Logged in as ${c.user.tag}`);
});
client.on(Events.InteractionCreate, async (interaction) => {
if (interaction.isChatInputCommand() && interaction.commandName === 'button') {
const row = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId('click').setLabel('Click me').setStyle(ButtonStyle.Primary));
await interaction.reply({ content: 'Press the button:', components: [row] });
}
if (interaction.isButton() && interaction.customId === 'click') {
db.prepare('INSERT INTO clicks (user_id, count) VALUES (?, 1) ON CONFLICT(user_id) DO UPDATE SET count = count + 1').run(interaction.user.id);
const { count } = db.prepare('SELECT count FROM clicks WHERE user_id = ?').get(interaction.user.id);
await interaction.reply({ content: `You clicked ${count} times.`, flags: MessageFlags.Ephemeral });
}
});
client.login(process.env.DISCORD_TOKEN);
Python (discord.py)
requirements.txt (SQLite is built into Python):
discord.py
python-dotenv
app.py:
import os
import sqlite3
import discord
from discord import app_commands
from dotenv import load_dotenv
load_dotenv()
db = sqlite3.connect("data.db")
db.execute("CREATE TABLE IF NOT EXISTS clicks (user_id INTEGER PRIMARY KEY, count INTEGER NOT NULL DEFAULT 0)")
db.commit()
class Clicker(discord.ui.View):
def __init__(self):
super().__init__(timeout=None) # the button keeps working, also after a restart
@discord.ui.button(label="Click me", style=discord.ButtonStyle.primary, custom_id="click")
async def click(self, interaction: discord.Interaction, button: discord.ui.Button):
db.execute("INSERT INTO clicks (user_id, count) VALUES (?, 1) "
"ON CONFLICT(user_id) DO UPDATE SET count = count + 1", (interaction.user.id,))
db.commit()
(count,) = db.execute("SELECT count FROM clicks WHERE user_id = ?", (interaction.user.id,)).fetchone()
await interaction.response.send_message(f"You clicked {count} times.", ephemeral=True)
class Bot(discord.Client):
def __init__(self):
super().__init__(intents=discord.Intents.default())
self.tree = app_commands.CommandTree(self)
async def setup_hook(self):
self.add_view(Clicker())
await self.tree.sync()
bot = Bot()
@bot.tree.command(description="Show a button")
async def button(interaction: discord.Interaction):
await interaction.response.send_message("Press the button:", view=Clicker())
bot.run(os.getenv("DISCORD_TOKEN"))
Run it on ServerSpark
- Put your token in a
.envfile:DISCORD_TOKEN=your-token-here. Never share it. - Upload the files under Files in SparkPanel (or use SFTP).
- Under Settings, check the startup file:
index.js(Node.js) orapp.py(Python). - Click Start. Packages are installed automatically; the console shows Logged in as … or any error.
Type /button in your Discord server. A new slash command can take a minute to show up.
data.db is a normal file in your bot's folder. Download it under Files now and then as an extra copy, especially before big changes.Frequently asked questions
Is SQLite enough, or do I need MySQL? For most bots (one bot, up to thousands of servers) SQLite is fine and much simpler. You'd only need a separate database server when several programs write to the same data at once.
The button says "This interaction failed". The bot didn't reply within 3 seconds, or it was offline. Check the console in SparkPanel for an error.
New to bots? Start with Make a Discord bot with JavaScript or in Python, then read Run your Discord bot 24/7.