CommandKit uses a convention-based file structure that automatically discovers commands, events, and middleware. Understanding this structure helps you organize your bot efficiently.
Basic Structure
Here’s the recommended project structure for a CommandKit bot:
.
├── src/
│ ├── app/
│ │ ├── commands/
│ │ │ ├── ping.ts
│ │ │ └── (moderation)/
│ │ │ ├── ban.ts
│ │ │ ├── kick.ts
│ │ │ └── +middleware.ts
│ │ └── events/
│ │ ├── clientReady/
│ │ │ └── log.ts
│ │ └── messageCreate/
│ │ ├── give-xp.ts
│ │ └── log-message.ts
│ └── app.ts
├── .env
├── .gitignore
├── commandkit.config.ts
├── package.json
└── tsconfig.json
File Conventions
app.ts
The src/app.ts (or app.js) file is your application’s entry point. It exports your Discord.js client instance:
import { Client } from 'discord.js';
const client = new Client({
intents: ['Guilds', 'GuildMembers', 'GuildMessages', 'MessageContent'],
});
// Optional: Override the default DISCORD_TOKEN environment variable
client.token = process.env.MY_BOT_TOKEN;
export default client;
Do not call client.login() in this file. CommandKit handles the login process automatically.
Commands Directory
The src/app/commands/ directory contains all your bot commands. Each command is a separate file:
src/app/commands/
├── ping.ts # /ping command
├── userinfo.ts # /userinfo command
└── (moderation)/ # Category grouping
├── ban.ts
├── kick.ts
└── mute.ts
Key points:
- Each file name should match the command name
- Files automatically register as commands when they export the required handlers
- Use category directories (wrapped in parentheses) to organize related commands
Events Directory
The src/app/events/ directory organizes Discord.js event handlers. Each event gets its own directory:
src/app/events/
├── clientReady/
│ └── log.ts
├── messageCreate/
│ ├── give-xp.ts
│ └── anti-spam.ts
└── guildMemberAdd/
├── send-welcome.ts
└── assign-role.ts
Key points:
- Directory names must match Discord.js event names exactly
- Multiple handlers can exist for the same event
- Handlers execute in alphabetical order by filename
Special Files
+middleware.ts
Middleware files control command execution flow:
src/app/commands/(moderation)/+middleware.ts
import type { MiddlewareContext } from 'commandkit';
export async function beforeExecute(ctx: MiddlewareContext) {
// Check if user has permission
const hasPermission = ctx.interaction?.memberPermissions?.has('ModerateMembers');
if (!hasPermission) {
if (ctx.isChatInputCommand()) {
await ctx.interaction.reply({
content: 'You need Moderate Members permission to use this command.',
ephemeral: true,
});
}
return ctx.cancel();
}
}
Middleware types:
+middleware.ts - Applies to all commands in the same directory and subdirectories
+global-middleware.ts - Applies to all commands in your bot
+<command>.middleware.ts - Applies to a specific command
(category) Directories
Use parentheses to create command categories without affecting the command path:
src/app/commands/
├── (moderation)/
│ ├── ban.ts # Creates /ban (not /moderation/ban)
│ └── kick.ts # Creates /kick
└── (fun)/
├── meme.ts # Creates /meme
└── joke.ts # Creates /joke
Categories help organize your code without changing command names.
Configuration File
The commandkit.config.ts file customizes CommandKit behavior:
import { defineConfig } from 'commandkit/config';
export default defineConfig({
// Your configuration options
});
For available options, see the Configuration documentation.
Environment Variables
Store sensitive data in .env:
DISCORD_TOKEN=your_bot_token_here
DISCORD_CLIENT_ID=your_client_id_here
DATABASE_URL=your_database_url_here
Never commit .env files to version control. Add them to .gitignore.
Best Practices
Use TypeScript
TypeScript provides better type safety and autocomplete for CommandKit and Discord.js APIs.
Organize with categories
Group related commands in category directories to keep your codebase maintainable.
Split event handlers
When an event needs multiple actions, create separate handler files for each responsibility.
Keep commands focused
Each command file should handle one specific task. Break complex commands into smaller ones.