Learn to Code via Tutorials on Repl.it

← Back to all posts
Making a discord bot using the discord.js Commando framework
TheDrone7 (548)

Discord.js Commando Framework tutorial

First of all, I recommend you all that you first go through the basics of JavaScript and Node.js from anywhere you'd like to though I personally recommend https://www.w3schools.com/ . Also, you should know how to create discord apps at https://discordapp.com/developers/applications/me and should've already invited the bot to your test server, this is only a tutorial for the commando framework, not the whole bot thing.

Next, let's get started

  • Step 1: Setting up the project

    1. Create a new folder (Make sure there are no spaces in your folder name) in your system and open command prompt or power shell in the folder.

    2. Run the command npm init and fill out the form, If you don't know what you're doing, then leave everything to default and type in you name when it asks for author.

      PS E:\tutorial-bot> npm init
      This utility will walk you through creating a package.json file.
      It only covers the most common items, and tries to guess sensible defaults.
      
      See `npm help json` for definitive documentation on these fields
      and exactly what they do.
      
      Use `npm install <pkg>` afterwards to install a package and
      save it as a dependency in the package.json file.
      
      Press ^C at any time to quit.
      package name: (tutorial-bot)
      version: (1.0.0)
      description: A new discord bot
      entry point: (index.js)
      test command:
      git repository:
      keywords:
      author: HS
      license: (ISC)
      About to write to E:\tutorial-bot\package.json:
      
      {
        "name": "tutorial-bot",
        "version": "1.0.0",
        "description": "A new discord bot",
        "main": "index.js",
        "scripts": {
          "test": "echo \"Error: no test specified\" && exit 1"
        },
        "author": "HS",
        "license": "ISC"
      }
      
      
      Is this ok? (yes)
      PS E:\tutorial-bot>
  1. After this, you will see a new file named package.json in your folder.

  2. Now use the following command to install the required libraries

    PS E:\tutorial-bot> npm install --save discord.js discord.js-commando fs sqlite path
  3. Now you'll see a new folder named node-modules in your bot's folder and you're ready to start coding the bot.
  • Step 2 : Writing the index.js file

    1. Create a new file in your bot's folder called index.js and open it with your favourite text editor.

    2. Now write the following code in the beginning of your index.js file.

      const commando = require('discord.js-commando')
      const path = require('path')
      const sqlite = require('sqlite')

      These lines will import the necessary libraries to use.

    3. Next, write the following code

      const client = new commando.CommandoClient({
          owner: '374886124126208000', // Your ID here.
          commandPrefix: '==', // The prefix of your bot.
          unknownCommandResponse: false, // Set this to true if you want to send a message when a user uses the prefix not followed by a command
      })

      This will create a CommandoClient Object which is an extension of discord.js.Clientclass and set the owner of the bot as yourself to allow you to use the owner only commands that come built-in with Commando.

    4. Now we will import the default commands for our bot.

      client.registry.registerDefaults()
    5. Now let's make a handler that displays a message in the console when the bot is logged in and ready to use.

      client.on('ready',()=>{
          console.log(`Logged in and ready to be used.. use "${client.commandPrefix}help".`)
      })
    6. Next, set up the settings provider, Commando comes with built-in sqlite settings provider to allow default commands like prefix work properly.

      client.setProvider(
          sqlite.open(path.join(__dirname, 'settings.sqlite3')).then(db => new Commando.SQLiteProvider(db))
      ).catch(console.error);
    7. Last of all, login the bot

      client.login("BOT_TOKEN")
  • Testing the defaults

    1. Run the bot by using the command node index in your console.

    2. After a while you will see a message similar to this: -

      PS E:\tutorial-bot> node index
      Logged in and ready to be used.. use "==help".

      You will also observe that your bot comes online so it's ready to be checked out.

    3. Use the help command which in my case is ==help

      It shows something like this in your DMs: -

      To run a command in *Server Name*, use == command or @Bot command. For example, == prefix or @Bot prefix.
      To run a command in this DM, simply use command with no prefix.
      
      Use help <command> to view detailed information about a specific command.
      Use help all to view a list of all commands, not just available ones.
      
      Available commands in *Server Name*
      
      Commands
      groups: Lists all command groups.
      enable: Enables a command or command group.
      disable: Disables a command or command group.
      reload: Reloads a command or command group.
      load: Loads a new command.
      unload: Unloads a command.
      
      Utility
      help: Displays a list of available commands, or detailed information for a specified command.
      prefix: Shows or sets the command prefix.
      ping: Checks the bot's ping to the Discord server.
      eval: Executes JavaScript code.

      Details

      • groups: The commands in a commando bot are grouped together under categories. the group command can be used the list these categories.

      • enable/disable: Commando framework comes with an in-built feature of enabling/disabling commands in different guilds, these commands do the job.

      • load/unload: These commands can be used to register commands from outside the code.

      • reload: This command can be used to reload a command after you've made changes to the code to refresh it.

      • help: The in-built help function ( very detailed ).

      • prefix: Commando also comes with a feature to change the default prefix in different servers, the prefix command helps the users do it.

      • ping: Does exactly what help says.

      • eval: runs the code passed as an extension of the index.js file and returns the output ( recommended not to use ).

        These are the commands that come built-in with commando framework.

  • Creating your own commands

    1. First of all, create a folder named commands in your bot's root directory.

    2. Next make the following change in your code

      client.registry.registerDefaults()

      to

      client.registry.registerDefaults()
      	.registerGroups([
              ['test', 'Starter Commands']
      	])
      	.registerCommandsIn(path.join(__dirname,"commands"))

      This will create a new group named Starter Commands for your bot which can be referred to in the code by the name test and also read the files inside the commands folder and treat them as commands for the bot.

    3. Inside the commands folder, create another folder named test and inside the test folder, create a file named foo.js as the first command will be a simple foo-bar command.

    4. Open the foo.js file and change it's contents to

      const { Command } = require('discord.js-commando')
      
      class fooCommand extends Command{
      
          constructor(client){
      
              super( client, {
                  name: 'foo',
                  memberName: 'foo',
                  aliases: ['f'],
                  group: 'test',
                  description: 'Responds with "bar".',
                  details: 'The traditional foo-bar.',
                  examples: ['==foo','==f']
              })
      
          }
      
          run(msg){
              msg.say('bar')
          }
      
      }
      
      module.exports = fooCommand
      Details
      • The first line imports the predefined Command class from the Commando Framework.

      • Next, we created the command as a extension of the Command class.

      • The constructor is run as soon as our index.js reads this file. Inside our constructor, we set the basic details about our command.

        name, memberName: set the name of the command.

        aliases: sets what other commands can be used to do the same thing.

        description, details: describe what the command does.

        examples: sets an example for the user on how to use the command.

        group: sets our command will be part of which command group.

      • The next part is the run method, it is called whenever the user uses the command, the parameter msg is the message sent by the user, it's of the type CommandoMessage.

        We make our bot respond with barwhenever the user uses the foo command.

      • Finally, module.exports = fooCommand exports the command making it readable by our index.js file.
    5. Now, let's test out our foo command.

      Run the bot using node index and use the help command.

      You will see something new at the end of the help menu

      Starter Commands
      foo: Responds with "bar".

      Let's use help about our command, use the help foo command. You should see something like: -

      __Command **foo:**__ Responds with "bar".
      
      **Format:** == `foo` or `@Bot foo`
      **Aliases:** f
      **Group:** Starter Commands (`test:foo`)
      **Details:** The traditional foo-bar.
      **Examples:**
      ==foo
      ==f

      Let's use our command now, there are 4 ways to do it now.

      • Use ==foo or ==f in a server
      • Use foo or f in DMs

      You will see that the bot responds with bar wherever you use the command.


  1. Now that we are done with one command, let's make another one that takes in input (arguments) from the user.

  2. Create a new file named say.js in your test folder.

  3. Write the following code in the say.js file.

    const {
        Command
    } = require('discord.js-commando')
    
    class sayCommand extends Command {
    
        constructor(client) {
    
            super(client, {
                name: 'say',
                memberName: 'say',
                group: 'test',
                aliases: ['echo', 'repeat'],
                description: 'A command that repeats whatever you say.',
                details: "Make me repeat your wordsmaking it look like I'm a parrot",
                examples: ['==say Hello World', '==repeat Who Am I?'],
                clientPermissions: ["MANAGE_MESSAGES"],
                args: [{
                    key: 'text',
                    prompt: 'What do you wish for me to say?',
                    type: 'string'
                }]
            })
    
        }
    
        run(msg, { text }) {
            msg.say(text)
            return msg.delete()
        }
    
    }
    
    module.exports = sayCommand
    Let's see what's new!
    • client_permissions: defines a list of permissions that your not will need for the command to work properly.
    • args: Defines what arguments the user has to enter.
      • key: defines the name of the argument.
      • prompt: defines what the bot will say if the user has not provided the argument
      • type: defines the type of the argument.
    • The run method now has 2 parameters, the second one is the arguments, we are asking the user to pass.
    • msg.delete()deletes the message sent by the user.
  4. Let's test out our say command
    If you use the help command now, you will see a new entry at the bottom for the say command.

    Use help say before using the command.

    You should see something similar to: -

    __Command **say:**__ A command that repeats whatever you say.
    
    **Format:** == `say <text>` or `@Bot say <text>`
    **Aliases:** echo, repeat
    **Group:** Starter Commands (`test:say`)
    **Details:** Make me repeat your words making it look like I'm a parrot
    **Examples:**
    ==say Hello World
    ==repeat Who Am I?

    Notice how Commando prepared the format for how to use the command, trust me it's a handy feature.

    Use the say command now without passing any arguments.

    You will see that the bot asks you for the text to say, also with a message like

    Respond with `cancel` to cancel the command. The command will automatically be cancelled in 30 seconds.

    This is another feature of Commando framework - command cancellation.

    You can either say something for the bot to repeat it or wait for 30 seconds to cancel the command or say cancel yourself.

    You can also pass on the argument while using the command as in the examples.

  • Validating and throttling

    Now let's think, what if the user was trying to send links or spam in the server using our say command?

    That can easily be prevented by validating the say command and making sure that there was no link in the argument passed.

    As for the spam, it can be prevented by throttling i.e. making sure that the command is not used more than a specified number of times in a specified amount of time.

    Here's a sample code (This is modified say.js file) : -

    const {
        Command
    } = require('discord.js-commando')
    
    class sayCommand extends Command {
    
        constructor(client) {
    
            super(client, {
                name: 'say',
                memberName: 'say',
                group: 'test',
                aliases: ['echo', 'repeat'],
                description: 'A command that repeats whatever you say.',
                details: "Make me repeat your wordsmaking it look like I'm a parrot",
                examples: ['==say Hello World', '==repeat Who Am I?'],
                clientPermissions: ["MANAGE_MESSAGES"],
                args: [{
                    key: 'text',
                    prompt: 'What do you wish for me to say?',
                    type: 'string',
                    validate: text=>{
                        if(text.indexof("http://") > -1 || text.indexOf("https://") > -1)
                            return "You are trying to send a link." // Message to display when invalid argument has been passed should be returned
                        else
                            return true // true should be returned when the argument is valid
                    }
                }],
                throttling: {
                    duration: 60, // This is the duration in seconds
                    usages: 2 // Allowed number of usages in the given duration
                }
            })
    
        }
    
        run(msg, { text }) {
            msg.say(text)
            return msg.delete()
        }
    
    }
    
    module.exports = sayCommand
    Now let's see: -
    • argument.validate: a function that checks for validation of the argument passed. Returns true when valid and the error message when invalid.
    • throttiling: an object that specifies how many usages in how much duration of time are allowed.
  • Messing with the defaults

    You can also modify the default commands: -

    You can find them at

    YourBotDirectory/node_modules/discord.js-commando/src/commands/

    In there, you will see 2 folders containing the command files.

    • /util/
      • eval.js - enables the owner to run javascript code from discord.
      • help.js - shows help for the various commands.
      • ping.js - displays the bot's ping to the discord server.
      • prefix.js - changes the prefix for the server ( guild Only command ).
    • /commands/
      • enable.js - enables a command in a server.
      • disable.js - disables a command in a server.
      • groups.js - lists all command groups.
      • load.js - loads a new command.
      • reload.js - reload a command.
      • unload.js - unloads a command.

That's all you need to know to get started, put your imagination to the test and make amazing bots. Here's the link to the official docs for more reference: https://discord.js.org/#/docs/commando/master/general/welcome
Also here's a link to a Commando bot by @kpostal10 named Bug Bot just for reference: https://repl.it/@kpostal10/BugBot

Commentshotnewtop
kpostal10 (17)

Looks good, warning to anyone that follows this tutorial on repl.it, using sqlite as the settings provider might break or become corrupt.

amasad (1374)

@kpostal10 thanks for the warning. @basicer is working on a new database system that's going to be 🔥

Nanowrimoijk (31)

how do i use the npm init command? if you run it in the terminal i keep getting an error.

TheDrone7 (548)

@Nanowrimoijk if you're using repl.it, you don't, use the package manager tab to install the listed packages.

Nanowrimoijk (31)

@TheDrone7 so is there a list somewhere? or do i need to just run the require variables?

TheDrone7 (548)

@Nanowrimoijk you can refer to the npm install command for reference. Each library is listed in the command separated by a space, search for each of those libraries in the package manager and install them.

Nanowrimoijk (31)

@TheDrone7 this?

E:\tutorial-bot> npm install --save discord.js discord.js-commando fs sqlite path
TheDrone7 (548)

@Nanowrimoijk yes as you can see, the libraries needed are

  • discord.js
  • discord.js-commando
  • fs
  • SQLite
  • path
Nanowrimoijk (31)

@TheDrone7 is there anything special to get the 'help' command to work on repl.it? its not working for me

TheDrone7 (548)

@Nanowrimoijk no there is nothing special to it. It still works for me so your code night be bugged, go through it again and you'll eventually find out

pizzafox (0)

Command class names like fooCommand and sayCommand should be in pascal case since they are classes. There are also several other bugs in your code, I fixed them in this GitHub gist.

Additionally, you should never edit anything in node_modules since updating dependencies will overwrite anything in there. To modify the default commands, just don't register them. Instead, you can register your own if you'd like.

For other things that can't be solved by extending classes from Commando you can make a fork of the GitHub repository and use that in your bot.

TheDrone7 (548)

@pizzafox As for the Command Classes, I prefer keeping them that way. Also this tutorial is completely bug free, and all the difference I see in your gist and this is use of regular expressions, and its not really a good idea to use regular expressions in a tutorial as most people don't understand them. If you really found an actual bug, let me know.
Additionally, you can edit something in the node_modules, it's not a big deal ( unless you're using heroku ), also, going through the files in the module source, people might learn new ways of doing many things. Appreciate the info though.

kpostal10 (17)

@pizzafox As for the class name being captiol, it does not matter all you are doing is exporting the class object. Weather or not it is captiol will not affect the function of the bot. For how long I've been doing JS bots this is one of the better tutorials I've seen; Espically for commando. Also just because it is not regex does not mean it will not work the same. I like the fact that he showed that it can be more than one line in the validate function because a novice might do more custom validation in that check.

As for the other "bugs" you fixed I would like to know which ones they are? Because I pasted his code in a bot and it ran just fine as it is.

And for editing the node_modules that complitly fine. I've done it for my bot to add a header to the built in help method saying that this bot was coded in commando and who made it.

pizzafox (0)

@kpostal10 For starters, the bot doesn't check if it can delete the command message. Also, it should return the response message.

Knowing you can make the validation function more than one line is basic JavaScript.

If you ever run your bot on another host or Commando has an update to the help command, your changes will be lost. I strongly suggest you move it to a separate command like I did in my bot

TheDrone7 (548)

@pizzafox first of all, it does check if it can delete the command message, instead of doing lazy things like https://gist.github.com/pizzafox/ad192e8519c69f63565980e446a13ecc, you should try doing a little hard work, returning the response message is optional, if not shown properly like in your gist, people might not even understand if it's a function, and as I said, this is not an absolute beginner tutorial, but it's still a tutorial, doing things like what you did with your bot might still be confusing moreover the bot you linked does exactly same as the built-in help command. This tutorial is not for pros, it's for everyone who knows the basics.
You might wanna give it a thought about what you say and maybe do the honor of reading the whole thing.

pizzafox (0)

@TheDrone7 The client permissions weren't there when I copied your command to make my edits. It seems you tried to add it in after I posted my comment. Make sure you change it from client_permissions to clientPermissions.

The help command I posted actually has a few new features, which you can see in the run function.

As an experienced Commando user, I'm just trying to improve this tutorial to help out newcomers. I apologise if my tone seemed critical.

kpostal10 (17)

@pizzafox Nothing wrong with being critical about a post, there is just a right and wrong way to appraoch it. Dont want to come off sounding like a "know-it-all" but you also want to make it to where what you are saying makes sense and is contributing (not taking away from) the post.
Thanks for providing another perspective to the bot.
Also @TheDrone7 might want to check the docs:
https://discord.js.org/#/docs/commando/master/class/Command?scrollTo=clientPermissions
It is clientPermissions

This is a really nice list of all the things you can put when you make a command in the constructor: https://discord.js.org/#/docs/commando/master/typedef/CommandInfo

TheDrone7 (548)

@pizzafox IDK but for some reason client_permissions was working fine for me locally. Also, it was there from the start, I never changed it. And, I also apologise for trying to judge you. 😅
Again, regex is something that might badly confuse the "newcomers".