Skip to main content
Version: 1.x

Introduction

CommandKit Logo
support discord servernpm versionnpm downloads

The problem

Every time you start a new discord.js bot, you end up solving the same problems from scratch:

  • Writing a command handler that reads files, registers slash commands, and routes interactions
  • Building an event handler that loads listeners and manages their lifecycle
  • Wiring up interaction collectors for buttons, select menus, and modals — then cleaning them up
  • Manually syncing command definitions with Discord's API every time you change something
  • Setting up the same project structure, over and over

If you've built more than one bot, you know the drill. Hours of boilerplate before you write a single line of actual bot logic. And if you're a beginner, figuring all of this out for the first time is overwhelming.

How is this different from other frameworks?

There's no shortage of discord.js frameworks out there, but most of them solve a very narrow problem: they load your command and event files so you don't have to write a file reader yourself. You instantiate their handler class, point it at a folder, and that's about it. The rest — project structure, compilation, component handling, command syncing — is still on you.

Frameworks like Sapphire go further and have decent features, but they're built around a heavy object-oriented design. Everything is a class. Commands extend base classes, listeners extend base classes, preconditions extend base classes. It works, but it demands a lot of boilerplate and a specific programming style that not everyone wants.

CommandKit takes a fundamentally different approach. Instead of being a library you wire into your own setup, it works like a proper meta-framework — think Next.js for Discord bots. It ships with a smart CLI that handles bundling, TypeScript/JSX compilation, hot-reloading, and command registration automatically. You don't configure a bundler. You don't set up tsconfig.json for JSX. You don't write glue code to connect things together. You run commandkit dev, and everything just works.

This is the key difference: most discord.js frameworks are loaders. CommandKit is a framework — it manages the entire development lifecycle, from project scaffolding to production builds, so you can focus entirely on your bot's logic.

Convention over configuration

CommandKit follows a convention-over-configuration philosophy. Instead of requiring you to wire things together with config files, decorators, or registration calls, it uses sensible defaults and file-system conventions that just work.

Put a file in src/app/commands/ — it's a command. Put a file in src/app/events/ — it's an event listener. Export a chatInput function — it handles slash commands. Export a message function in the same file — it handles prefix commands too. There's nothing to register, no class to extend, no decorator to apply.

This matters because Discord bot projects aren't complex enterprise applications — they shouldn't need complex enterprise tooling. You want to write bot logic, not plumbing. Convention-over-configuration means the framework already knows what to do with your code based on where it is and what it exports, so you skip the setup entirely and go straight to building.

If you've used Next.js, this will feel familiar: file-system routing, zero-config defaults, and a CLI that handles the build pipeline. Same idea, applied to Discord bots.

What makes it actually useful

Command and event handling — done for you

This is the core of CommandKit. Drop your command files in a folder, export a function, and they just work. Slash commands, context menu commands, and even prefix (message) commands are all supported under a single unified command structure — no separate handler for each type. Commands are automatically registered and kept in sync with Discord. Events work the same way: create a file, export a listener, and CommandKit handles the rest.

No more writing your own loadCommands() and loadEvents() utilities for every project.

JSX components — clean, readable Discord UI code

If you've used React, you already know how much cleaner JSX makes UI code. CommandKit brings that same idea to Discord. Instead of chaining ActionRowBuilder, ButtonBuilder, Poll, and friends — which gets unreadable fast with even moderately complex layouts — you write declarative JSX that looks like what it produces.

This isn't a gimmick. discord.js builder chains become genuinely hard to maintain as your components grow. JSX fixes that.

Built-in component handlers — forget about collectors

This is where CommandKit goes beyond a basic command handler. Buttons, select menus, and modals get onClick, onSelect, and onSubmit handlers that are directly bound to the component. No more setting up InteractionCollector instances, managing timeouts, filtering interactions, and cleaning up afterwards.

You define the component and its behavior in one place. CommandKit handles the interaction routing for you.

Command middlewares — run logic before and after execution

Need to check permissions, log analytics, or gate commands behind a cooldown? Middlewares let you run code before and/or after any command executes, without modifying the command itself. This is a step above what a typical command handler gives you — it's a proper middleware layer, similar to what you'd find in web frameworks like Express.

Prefix commands — unified with slash commands

CommandKit supports message-based (prefix) commands within the same command file that already handles slash commands, user context menus, and message context menus. One file, all command types. No separate prefix command handler needed.

Caching with Redis support

CommandKit ships with a @commandkit/cache plugin that provides a customizable caching layer. Need fast in-memory caching? Done. Need Redis-backed caching for persistence across restarts? Also done. No need to wire up your own caching logic. Just attach the 'use cache' directive to a function and call it a day!

// The result of this function is automatically cached
async function fetchUserData(userId: string) {
'use cache';
return db.users.findUnique({ id: userId });
}

Learn more about caching in the cache plugin documentation.

Plugin system and custom events

CommandKit is extensible through plugins. Plugins can hook into the framework lifecycle, add new behaviors, and even emit custom events — for example, a plugin could listen to an external API (a payment webhook, a game server, etc.) and fire events that your bot code can react to. This isn't just a wrapper around node:events; it's a structured extension point that lets plugins and your bot code communicate through a well-defined event system.

Other official plugins include @commandkit/i18n for localization and @commandkit/analytics for usage tracking.

AI-powered command execution

The @commandkit/ai plugin lets users interact with your bot through natural language. Instead of memorizing slash command names and options, users can just talk to your bot — and the AI figures out which command to run and with what parameters.

Under the hood, it uses the AI SDK to connect to models like Google Gemini, OpenAI, and others. You define an ai export in your command file with a Zod schema describing the expected parameters, and the AI handles the rest — parsing natural language into structured input and calling your command function.

src/app/commands/greet.ts
import type { AiConfig, AiCommand } from '@commandkit/ai';
import { z } from 'zod';

export const aiConfig: AiConfig = {
inputSchema: z.object({
username: z.string().describe('The username to greet'),
}),
};

export const ai: AiCommand<typeof aiConfig> = async (ctx) => {
const { username } = ctx.ai.params;
await ctx.message.reply(`Hello, ${username}!`);
};

Now users can say @bot say hi to John and it just works. You also get built-in tools (fetching users, channels, guild info), custom tool support, lifecycle hooks, and per-user model selection. It's a full AI integration layer, not just a chatbot wrapper.

Learn more in the AI plugin documentation.

TypeScript and JavaScript — zero config

CommandKit works with both TypeScript and JavaScript out of the box — including native JSX support with no configuration. No fiddling with tsconfig.json, no setting up a separate build step, no wiring up a bundler. The CLI handles compilation, bundling, hot-reloading, and project scaffolding. Run commandkit dev and start building.

Who is this for?

  • Beginners who don't want to spend hours building command/event handlers before they can do anything useful
  • Experienced developers who are tired of rebuilding the same boilerplate for every new bot project
  • Teams and freelancers working on client projects who need a reliable, structured foundation they can build on quickly

CommandKit has been used in production client projects and has saved hours of setup time on each one. It's not overhead — it's the setup work you'd do anyway, already done well.

Get started

npm create commandkit

Then run commandkit dev and start building.

Support and suggestions