You want a Discord bot that remembers reminders even after the bot restarts. An in-memory bot loses all scheduled reminders when the process stops. This article explains how to build a reminder system using a persistent database backend so reminders survive crashes and reboots. You will learn to store reminder data in SQLite, schedule tasks with a loop, and handle user commands.
Key Takeaways: Building a Persistent Discord Reminder Bot
- SQLite database for storage: Stores reminder time, channel ID, user ID, and message text so data persists across restarts.
- Asyncio loop with task scheduling: Checks the database every few seconds and sends due reminders without blocking the bot.
- Command handling with discord.py: Uses
!remindmeand!listreminderscommands to create and view reminders.
How a Persistent Reminder Bot Works
A persistent reminder bot stores each reminder in a database file instead of only in memory. When the bot starts, it loads all pending reminders from the database and reschedules them. The bot then runs a background loop that checks for due reminders every few seconds. When a reminder is due, the bot sends a message to the specified channel and deletes the row from the database.
The core components are:
Database Schema
You need a table with columns for a unique ID, the target time as a Unix timestamp, the channel ID, the user ID, and the reminder message. Using SQLite keeps the setup simple because Python includes the sqlite3 module in its standard library.
Background Task Loop
Discord bots built with discord.py run on an asyncio event loop. You create a background task that runs every 10 seconds. The task queries the database for rows where the timestamp is less than the current time. For each due reminder, the bot sends the message and deletes the row.
Command Handlers
You need at least two commands. The !remindme command parses a time string and a message, inserts a new row into the database, and confirms the reminder. The !listreminders command fetches all pending reminders for the user and displays them.
Steps to Build the Reminder Bot
- Set up the project and install discord.py
Create a new folder and a virtual environment. Runpip install discord.pyto install the library. No extra database library is needed because sqlite3 is built into Python. - Create the database helper module
Write a file nameddatabase.py. Inside, define a functioninit_db()that creates the reminders table if it does not exist. The table should have columns:id INTEGER PRIMARY KEY AUTOINCREMENT,timestamp INTEGER,channel_id INTEGER,user_id INTEGER, andmessage TEXT. - Write the insert and delete functions
In the same module, writeadd_reminder(timestamp, channel_id, user_id, message)andremove_reminder(reminder_id). Use parameterized queries to prevent SQL injection. - Write the query function for due reminders
Writeget_due_reminders()that returns all rows wheretimestamp <= current_time. Also writeget_user_reminders(user_id)for the list command. - Create the main bot script
Inbot.py, import discord, commands from discord.ext, asyncio, and your database module. Initialize the bot withcommands.Bot(command_prefix='!'). - Implement the background reminder checker
Use the@tasks.loop(seconds=10)decorator from discord.ext.tasks. Defineasync def check_reminders()that callsget_due_reminders(). For each row, send the message to the channel usingbot.get_channel(row[2]), then callremove_reminder(row[0]). - Add the !remindme command
Use@bot.command()and parse the time argument. Accept formats like30s,5m,1h. Convert to a Unix timestamp by adding the delay totime.time(). Insert the reminder into the database and reply with a confirmation. - Add the !listreminders command
Queryget_user_reminders(ctx.author.id). Format the results into an embed or plain text. If no reminders exist, reply with a simple message. - Start the bot
In theon_readyevent, callinit_db()and thencheck_reminders.start(). Run the bot withbot.run('YOUR_TOKEN'). - Test the bot
Invite the bot to a test server. Type!remindme 10s Test messageand wait 10 seconds. The bot should send the reminder in the same channel. Restart the bot and verify that pending reminders still fire.
Common Issues and Edge Cases
Bot Sends Reminders Multiple Times
If the background loop runs faster than the database delete operation, the same reminder can be fetched twice. Use a lock or mark the reminder as sent with an additional boolean column. Alternatively, delete the row inside the same database transaction that reads it.
Time Parsing Errors
Users may type !remindme 5min instead of 5m. Write a robust parser that strips whitespace and accepts multiple formats. Use regex to extract the numeric value and the unit character, then convert accordingly.
Bot Loses Connection During a Reminder
If the bot disconnects while sending a reminder, the row remains in the database. After reconnection, the background loop will retry the reminder. This is acceptable for most use cases. To avoid duplicate sends, add a status column with values pending and sent. Update the status before sending, then delete after confirmation.
Large Number of Reminders
SQLite handles thousands of rows without issues. If you expect millions, consider switching to PostgreSQL. For a typical Discord server, SQLite is sufficient.
SQLite vs In-Memory Storage for Reminders
| Item | SQLite Database | In-Memory Dictionary |
|---|---|---|
| Data persistence | Survives bot restarts and crashes | Lost on restart or crash |
| Setup complexity | Single file, no external service | No setup needed |
| Query capabilities | SQL queries for filtering and sorting | Manual iteration over Python dict |
| Scalability | Good for thousands of reminders | Limited by RAM and process lifetime |
| Concurrent access | Handles multiple reads safely | Requires manual lock management |
SQLite is the better choice for any bot that needs to remember reminders across restarts. In-memory storage is only acceptable for temporary testing.
You can now build a Discord bot that stores reminders in a persistent SQLite database. The bot uses a background task loop to check for due reminders every 10 seconds and sends them reliably. For a next step, add a !cancelreminder command that deletes a specific reminder by ID. As an advanced improvement, implement a timezone column so users can set reminders in their local time zone.