Skip to main content
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:
src/app.ts
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:
commandkit.config.ts
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:
.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

1

Use TypeScript

TypeScript provides better type safety and autocomplete for CommandKit and Discord.js APIs.
2

Organize with categories

Group related commands in category directories to keep your codebase maintainable.
3

Split event handlers

When an event needs multiple actions, create separate handler files for each responsibility.
4

Keep commands focused

Each command file should handle one specific task. Break complex commands into smaller ones.

Build docs developers (and LLMs) love