Skip to main content
Version: 1.x

Middlewares

Middlewares in CommandKit allow you to execute code before and after command execution. This is incredibly powerful for implementing features like logging, authentication, permission checks, or any other cross-cutting concerns for your Discord bot.

CommandKit supports three different types of middleware files, each serving different scoping purposes for your commands.

Basic middleware structure

All middleware files follow the same export pattern. You can export beforeExecute and afterExecute functions that will run at their respective times during command execution.

src/app/commands/+middleware.ts
import { MiddlewareContext } from 'commandkit';

export function beforeExecute(ctx: MiddlewareContext) {
// This function will be executed before the command is executed
console.log(`User ${ctx.interaction.user.id} is about to execute a command`);
}

export function afterExecute(ctx: MiddlewareContext) {
// This function will be executed after the command is executed
console.log(
`Command execution completed for user ${ctx.interaction.user.id}`,
);
}

Stop command execution

You can stop a command from running by calling stopMiddlewares() in the beforeExecute function.

src/app/commands/+middleware.ts
import type { MiddlewareContext } from 'commandkit';

export function beforeExecute(ctx: MiddlewareContext) {
if (ctx.interaction.user.id !== '1234567890') {
// Conditionally stop command execution
console.log(`${ctx.commandName} will not be executed!`);
stopMiddlewares();
}

// Continue with command execution
console.log(`${ctx.commandName} will be executed!`);
}
tip

You can also use stopMiddlewares() inside a command function to stop any afterExecute middlewares from running.

In addition, you can also use stopMiddlewares() inside any afterExecute middleware function to stop any remaining middlewares from running.

warning

Calling stopMiddlewares() in a try/catch block may lead to unexpected behavior.

If you still want to use stopMiddlewares() in a try/catch block, you can use the isErrorType function to check if the error is an instance of the CommandKitErrorCodes.StopMiddlewares error.

src/app/commands/+middleware.ts
import type { MiddlewareContext } from 'commandkit';

export function beforeExecute(ctx: MiddlewareContext) {
try {
// code that may throw an error

stopMiddlewares(); // conditionally stop the middleware chain
} catch (error) {
if (isErrorType(error, CommandKitErrorCodes.StopMiddlewares)) {
// if stopMiddlewares() is called in the try block, throw it so CommandKit can stop the middleware chain
throw error;
}

// this means that the code threw the error, and stopMiddlewares() was not called
// the rest of the middlewares will be executed as normal
console.error(error);
}
}

Middleware types

Directory-scoped middleware

Create a +middleware.ts file in any commands directory to apply middleware to all commands within that directory and its subdirectories.

src/app/commands/(Moderation)/+middleware.ts
import type { MiddlewareContext } from 'commandkit';

export function beforeExecute(ctx: MiddlewareContext) {
// This middleware will run before any moderation command
if (!ctx.interaction.member.permissions.has('KickMembers')) {
throw new Error('You need moderation permissions to use this command');
}
}

Command-specific middleware

For command-specific middleware, create a file named +<command-name>.middleware.ts where <command-name> matches your command file name.

src/app/commands/+ban.middleware.ts
import type { MiddlewareContext } from 'commandkit';

export function beforeExecute(ctx: MiddlewareContext) {
// This middleware only runs before the ban command
console.log('Ban command is about to be executed');
}

Global middleware

Create a +global-middleware.ts file in your commands directory to apply middleware to every command in your entire Discord bot.

src/app/commands/+global-middleware.ts
import type { MiddlewareContext } from 'commandkit';

export function beforeExecute(ctx: MiddlewareContext) {
// This middleware runs before ANY command in your bot
console.log(
`Command executed by ${ctx.interaction.user.tag} in ${ctx.interaction.guild?.name || 'DMs'}`,
);
}
tip

Middleware execution (both before and after) follows a hierarchy: command-scoped middlewares run first, then directory-scoped middlewares, and finally global middlewares.