npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

discmd-handler

v1.1.2

Published

discmd-handler is a lightweight and flexible command handler for Discord.js bots that simplifies the process of creating and managing commands.

Readme

While this package has not been tested on Windows, we encourage you to try it out and let us know of any issues you encounter. We value your feedback and would love to work with you to improve compatibility with Windows. If you're interested in contributing to this effort, we welcome your input and pull requests!

Table of contents

Introduction

discmd-handler is a lightweight and easy-to-use command handler for Discord.js bots. This package is designed to simplify the process of implementing a command handler in your Discord bot by providing a flexible and customizable framework that can handle a wide range of commands.

The package currently contains handlers for the commands that the developer uses. However, if you need support for other types of commands, you can make a feature request or contribute to the development of the package.

With discmd-handler, you can easily create and manage commands for your bot without having to write the same boilerplate code every time. The package is designed to be modular and flexible, allowing you to customize it to fit your specific needs.

Whether you're a beginner or an experienced developer, discmd-handler can help you save time and streamline your bot development process. Try it out today and see how easy it can be to implement a powerful command handler for your Discord bot!

Installation

Requirements

  • discord.js@14

Install

npm i discmd-handler     # npm
yarn add discmd-handler  # yarn
pnpm add discmd-handler  # pnpm

Basic usage

Setup:

import { Client, GatewayIntentBits } from "discord.js";
import { handleCommands } from "discmd-handler";

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
});

handleCommands({
  client,
  // All the paths are relative to process.cwd()
  commands: {
    ButtonCommands: "commands/button",
    ChatInputCommands: "commands/chat-input",
    MessageCommands: "commands/message",
    SelectMenuCommands: "commands/select-menu",
  },
  // prefix can be either a string or an array of strings or a function that return a string or array of strings
  // When using a function, the first param will be the `Message` instance.
  prefix: "!",
});

client.login();

Inside commands/chat-input/ping.js:

import { SlashCommandBuilder } from "discord.js";

/** @type {import("discmd-handler").ChatInputCommandInterface} */
export default {
  data: new SlashCommandBuilder()
    .setName("ping")
    .setDescription("Replies with pong!"),
  execute(interaction) {
    interaction.reply("Pong!");
  },
};

We use jsdoc @type tag to get autocompletion.

Other commands

Message Command

import {
  ActionRowBuilder,
  ButtonBuilder,
  ButtonStyle,
  SlashCommandBuilder,
  StringSelectMenuBuilder,
} from "discord.js";

/** @type {import("discmd-handler").MessageCommandInterface} */
export default {
  name: "components",
  description: "Sends a message with a button and a select menu",
  execute(data) {
    const button = new ButtonBuilder()
      .setCustomId("button#" + data.author.id) // Anything after # is considerd metadata for the command
      .setLabel("This is a button")
      .setStyle(ButtonStyle.Primary);

    const selectMenu = new StringSelectMenuBuilder()
      .setCustomId("selectMenu#" + data.author.id) // Anything after # is considerd metadata for the command
      .addOptions(
        { label: "Option 1", value: "opt1" },
        { label: "Option 2", value: "opt2" }
      );

    const buttonActionRow = new ActionRowBuilder().addComponents(button);
    const selectMenuActionRow = new ActionRowBuilder().addComponents(
      selectMenu
    );

    return data.channel.send({
      components: [buttonActionRow, selectMenuActionRow],
    });
  },
};

Button Command

/** @type {import("discmd-handler").ButtonCommandInterface} */
export default {
  // name should be the part of the customId before #
  // if there is no #, it should be the full customId
  name: "button",
  execute(interaction, metadata) {
    // metadata contains the text after the first # in the customId
    // In this case, its the id of the user who ran the !components command
    if (interaction.user.id !== metadata)
      return interaction.reply({
        content: "You cannot click that button",
        ephemeral: true,
      });

    return interaction.reply(`${interaction.user} clicked the button`);
  },
};

Select Menu Command

/** @type {import("discmd-handler").SelectMenuCommandInterface} */
export default {
  // name should be the part of the customId before #
  // if there is no #, it should be the full customId
  name: "selectMenu",
  execute(interaction, metadata) {
    // metadata contains the text after the first # in the customId
    // In this case, its the id of the user who ran the !components command
    if (interaction.user.id !== metadata)
      return interaction.reply({
        content: "You cannot use this select menu",
        ephemeral: true,
      });

    return interaction.reply(
      `${interaction.user} choose ${interaction.values[0]}`
    );
  },
};

Registering Slash Commands

This code should be in a seperate file. You should only run it when you want to register slash commands.

import { registerApplicationCommands } from "discmd-handler";

registerApplicationCommands({
  token: process.env.DISCORD_TOKEN,
  commands: {
    ChatInputCommands: "commands/chat-input",
  },
  // Omit this option if you want to register global commands
  guildId: "guild id of the dev server",
});

Guides and concepts

Working with CommonJs or TypeScript

All the examples above are given in ESModule. However, this package also supports CommonJs and TypeScript.

CommonJs

const { SlashCommandBuilder } = require("discord.js");

/** @type {import("discmd-handler").ChatInputCommandInterface} */
module.exports = {
  data: new SlashCommandBuilder()
    .setName("ping")
    .setDescription("Replies with pong!"),
  execute(interaction) {
    interaction.reply("Pong!");
  },
};

TypeScript

import { SlashCommandBuilder } from "discord.js";
import { ChatInputCommandInterface } from "discmd-handler";

export default {
  data: new SlashCommandBuilder()
    .setName("ping")
    .setDescription("Replies with pong!"),
  execute(interaction) {
    interaction.reply("Pong!");
  },
} satisfies ChatInputCommandInterface;

The satisfies keyword in typescript is introduced in version 4.9. If you are using older version, your code should look like this instead.

export default <ChatInputCommandInterface>{
  data: ...,
  execute(interaction) {
    ....
  },
}

Error handling

Currently, error handling is not customizable. If an error occurs while running the execute function, the default behavior is to log it to the console. However, we recognize the importance of providing users with the ability to customize error handling to better suit their needs. As such, we are actively working on a solution and plan to make it available in future versions.

Changelog

View the changelog at CHANGELOG.md