A clean, modular Discord bot template with TypeScript, featuring a command class pattern and single source of truth architecture.
- Single Source of Truth: Add commands in one place, automatically available everywhere
- TypeScript: Full type safety and modern JavaScript features
- Modular Commands: Self-contained command classes with built-in validation
- Environment Validation: Comprehensive startup checks with helpful error messages
- Auto-Generated Help: Commands self-document with metadata
- Contextual Logging: Detailed logging with class and function context
- Production Ready: Error handling, validation, and clean architecture
git clone <your-repo>
cd discord-bot-template
npm install
cp .env.example .env
Edit .env
with your bot credentials:
DISCORD_TOKEN=your_bot_token_here
DISCORD_CLIENT_ID=your_bot_client_id_here
DEVELOPER_IDS=your_user_id_here # Optional
NODE_ENV=development # Optional
npm run register # Register commands with Discord
npm run dev # Start development server
src/
├── core/
│ ├── Bot.ts # Main bot class
│ ├── Command.ts # Abstract command base
│ └── CommandManager.ts # Command management
├── commands/
│ ├── index.ts # ← Command registry (single source of truth)
│ ├── PingCommand.ts # Basic example
│ ├── InfoCommand.ts # Embed example
│ ├── ExampleCommand.ts # Advanced features
│ ├── HelpCommand.ts # Auto-generated help
│ └── DevCommand.ts # Developer tools
├── services/
│ ├── Logger.ts # Contextual logging
│ ├── DiscordApi.ts # API helper
│ └── Environment.ts # Config validation
├── index.ts # Entry point
└── register.ts # Command registration
// src/commands/MyCommand.ts
import { ChatInputCommandInteraction, SlashCommandBuilder } from 'discord.js';
import { Command, CommandHelpInfo } from '../core/Command.js';
export class MyCommand extends Command {
public readonly data = new SlashCommandBuilder()
.setName('mycommand')
.setDescription('My awesome command');
public readonly helpInfo: CommandHelpInfo = {
name: 'mycommand',
description: 'Does something awesome',
usage: '/mycommand',
examples: ['/mycommand'],
category: 'General'
};
public async execute(interaction: ChatInputCommandInteraction): Promise<void> {
await interaction.reply('Hello World!');
}
}
// src/commands/index.ts
import { MyCommand } from './MyCommand.js';
export const ALL_COMMANDS: Command[] = [
// ... existing commands
new MyCommand(), // ← Add here
];
That's it! Your command is automatically:
- ✅ Registered with Discord
- ✅ Available in the bot
- ✅ Listed in help system
- ✅ Validated and logged
/ping
- Basic ping/pong with latency/info
- Bot information and statistics/help [command]
- Auto-generated help system/example <subcommand>
- Advanced command examples/dev <info|test>
- Developer tools (requiresDEVELOPER_IDS
)
npm run build
- Compile TypeScriptnpm run dev
- Build and run with file watchingnpm run start
- Start production servernpm run register
- Register commands with Discordnpm run deploy
- Build, register, and start
Variable | Required | Description |
---|---|---|
DISCORD_TOKEN |
✅ | Bot token from Discord Developer Portal |
DISCORD_CLIENT_ID |
✅ | Bot client ID from Discord Developer Portal |
DEVELOPER_IDS |
❌ | Comma-separated user IDs for developer commands |
NODE_ENV |
❌ | Environment mode (defaults to production ) |
MIT License - See LICENSE file for details.
- Fork the repository
- Create your feature branch
- Commit your changes
- Push to the branch
- Create a Pull Request