Stop building from scratch. This template gives you a battle-tested foundation for any Discord community bot — with modular cogs, async PostgreSQL, a full XP/leveling engine, visual card generation, and a ticket system out of the box.
Getting Started · Features · Architecture · Customization · Contributing
| Category | What You Get |
|---|---|
| Modular Cog System | Plug-and-play architecture — add/remove features by editing one list in main.py |
| XP & Leveling | Message XP, voice XP, reaction XP, daily streaks, auto role promotion |
| Visual Cards | PNG rank cards, leaderboard cards, and welcome cards generated with Pillow |
| Ticket System | Persistent button panel, private channels, category selection, transcript on close |
| Announcements | Staff-only /announce with role ping options and confirmation flow |
| Giveaways | Button entry, random winner selection, XP rewards, persistent data |
| Event Logging | Auto-logs joins, leaves, message edits/deletes, role changes to staff channel |
| Welcome System | Auto-role assignment + visual welcome card + customizable greeting |
| Anti-Duplicate | PID file lock prevents multiple bot instances from running |
| Slash Commands | Modern Discord UI with app_commands — no prefix commands needed |
DiscordBotTemplate/
├── main.py # Entry point — PID lock, cog loader, slash sync
├── config.py # All IDs, constants, branding (single source of truth)
├── requirements.txt # Dependencies
├── .env.example # Environment template
├── start_bot.sh # tmux launcher script
│
├── cogs/ # Modular feature plugins
│ ├── logging_cog.py # Event logging (joins, edits, deletes, roles)
│ ├── welcome.py # Welcome embed + visual card + auto-role
│ ├── tickets.py # Persistent button ticket system + transcripts
│ ├── announce.py # Staff announcements with ping control
│ ├── leveling.py # Full XP system (msg/voice/reaction/daily)
│ └── giveaway.py # Giveaway creation + button entry + winner
│
├── shared/ # Platform-agnostic core
│ ├── db.py # AsyncPG connection pool + queries
│ ├── xp_engine.py # Level formula + atomic XP operations
│ ├── models.py # User & XPResult dataclasses
│ └── schema.sql # PostgreSQL schema (run once)
│
├── utils/
│ └── card_generator.py # Pillow-based visual card generation
│
└── data/ # JSON data files (quiz banks, etc.)
- One config, zero magic — All IDs, XP rates, and channel names live in
config.py - Async all the way — asyncpg, discord.py async, no blocking calls
- Atomic XP updates — Race-condition safe with PostgreSQL
UPDATE ... RETURNING - Persistent views — Buttons survive bot restarts via
custom_id - Phase-based deployment — Enable cogs incrementally as your community grows
- Python 3.10+
- PostgreSQL 14+
- A Discord bot token (create one here)
git clone https://github.com/djproject-id/DiscordBotTemplate.git
cd DiscordBotTemplate
pip install -r requirements.txtcp .env.example .envEdit .env:
DISCORD_TOKEN=your_bot_token_here
DATABASE_URL=postgresql://user:pass@localhost:5432/mybotEdit config.py:
GUILD_ID = 123456789 # Your server ID
ROLE_MODERATOR = 123456789 # Your moderator role ID
ROLE_ADMIN = 123456789 # Your admin role ID
# ... etcpsql -U your_user -d your_db -f shared/schema.sqlpython3 main.py
# Or use tmux (survives terminal close):
./start_bot.sh- Create
cogs/my_feature.py:
import discord
from discord import app_commands
from discord.ext import commands
import config
class MyFeatureCog(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
@app_commands.command(name="hello", description="Say hello!")
async def hello(self, interaction: discord.Interaction):
await interaction.response.send_message("Hello!")
async def setup(bot: commands.Bot):
await bot.add_cog(MyFeatureCog(bot))- Add to
main.py:
COG_MODULES = [
# ... existing cogs
"cogs.my_feature",
]- Restart the bot. Done.
The leveling curve in shared/xp_engine.py:
Level 2: 90 XP Level 10: 1,980 XP
Level 5: 510 XP Level 20: 9,660 XP
Level 15: 4,590 XP Level 30: 28,830 XP
Modify calc_xp_for_level() to adjust difficulty.
Edit these in config.py:
BOT_NAME = "MyBot"
BRAND_COLOR = 0x5865F2 # Embed color
BRAND_ICON_URL = "https://..." # Footer iconAnd in utils/card_generator.py:
BRAND_PALETTE = "blurple" # or "teal", "gold", "purple", etc.| Pattern | Example Cog | Key Technique |
|---|---|---|
| Event Listener | logging_cog.py |
@commands.Cog.listener() on events |
| Slash Command | announce.py |
@app_commands.command() with role checks |
| Persistent Button | tickets.py |
discord.ui.View(timeout=None) + custom_id |
| Scheduled Task | leveling.py |
@tasks.loop(seconds=60) for voice XP |
| JSON Persistence | giveaway.py |
Load/save JSON for lightweight data |
| Visual Output | leveling.py |
Pillow PNG → discord.File attachment |
| XP Integration | giveaway.py |
await add_xp(user_id, "discord", amount, "source") |
The shared/ layer is platform-agnostic — the same database schema, XP engine, and models work with both Discord and Telegram bots. Check out TelegramBotTemplate for the Telegram counterpart.
Users can link their Discord and Telegram accounts to share XP across platforms.
| Component | Technology |
|---|---|
| Bot Framework | discord.py 2.7+ |
| Database | PostgreSQL + asyncpg |
| Image Generation | Pillow (PIL) |
| Environment | python-dotenv |
Contributions are welcome! Here's how:
- Fork the repository
- Create a feature branch:
git checkout -b feat/amazing-feature - Commit your changes:
git commit -m "feat: add amazing feature" - Push to the branch:
git push origin feat/amazing-feature - Open a Pull Request
- Automod cog (spam detection, link filtering, bad word filter)
- Music/audio player cog
- Moderation cog (warn, mute, ban with audit log)
- Reaction roles cog
- Starboard cog
- Poll/voting cog
- Custom help command cog
- SQLite fallback for shared/db.py (no PostgreSQL needed)
- Docker + docker-compose setup
- Unit tests for XP engine and card generator
This project is licensed under the MIT License — see the LICENSE file for details.
Built with discord.py · Made for the community
If this template saved you time, consider giving it a star!