Skip to main content

Creating a basic command

In order to start registering commands you need to create a subdirectory called commands (lowercase!) in your entry point directory. If you were following Getting Started, it'll be src/commands.

Normally, you'd export one command per file to keep things organized. However, as we support various ways of exporting commands from the file (export class ..., export default class, module.exports = class ... and exports.MyCommand = class ...) you can export multiple commands from the same file.

info

Note that this doesn't create subcommands. We'll cover those in Plugin Subcommands

Create a ping.js file in your commands folder, which will send a message and then edit it with the elapsed time. Arguments and other features are covered in other pages.

Creating a command class

Let's start by creating the file for the command class. In your commands folder, create a file named ping.js (or ping.mjs / ping.ts if you're using ESM or TypeScript respectively). This command will send a message, and then edit it with the bot's WebSocket latency.

Your project directory should now look something like this:

├── node_modules
├── package.json
└── src
├── commands
│ └── ping.js
└── index.js

With the file created, we can start writing our commands by extending the Command class, from which all commands must be derived.

That said, here is an example of a ping command:

import { Command } from '@sapphire/framework';export class PingCommand extends Command {  public constructor(context: Command.Context, options: Command.Options) {    super(context, {      ...options,      name: 'ping',      aliases: ['pong'],      description: 'ping pong'    });  }}

Let's go over what is defined in the constructor in this code:

  • context: an object that contains file metadata required by the Piece class (which Command extends) in order to function.
  • name: by default, the name of the file without the extension, i.e. ping.js becomes ping, so there's no need to define it.
  • aliases: other ways users can call the command. You can have as many as you want!
  • description: some text that you can use to display when a "help" command is used.

There are many other properties available, all of which can be seen in the [CommandOptions] interface, but will also be explained in upcoming sections.

Creating the messageRun method

Commands have a messageRun method, which executes the command logic when it is invoked from a message. Define this below the command's constructor:

import { Command } from '@sapphire/framework';import type { Message } from 'discord.js';export class PingCommand extends Command {  public constructor(context: Command.Context, options: Command.Options) {    // ...  }  public async messageRun(message: Message) {    const msg = await message.channel.send('Ping?');    const content = `Pong from JavaScript! Bot Latency ${Math.round(this.container.client.ws.ping)}ms. API Latency ${      msg.createdTimestamp - message.createdTimestamp    }ms.`;    return msg.edit(content);  }}

Any discord.js code can be executed here since the Sapphire Framework is an extension of it. The command can be triggered with @bot ping or @bot pong (custom prefixes are mentioned in other documents).

Resulting code

Once you've set up the constructor and the messageRun method, your code should look like this:

import { Command } from '@sapphire/framework';import type { Message } from 'discord.js';export class PingCommand extends Command {  public constructor(context: Command.Context, options: Command.Options) {    super(context, {      ...options,      name: 'ping',      aliases: ['pong'],      description: 'ping pong'    });  }  public async messageRun(message: Message) {    const msg = await message.channel.send('Ping?');    const content = `Pong from JavaScript! Bot Latency ${Math.round(this.container.client.ws.ping)}ms. API Latency ${      msg.createdTimestamp - message.createdTimestamp    }ms.`;    return msg.edit(content);  }}