How I have Built Jeeves using Discord.js

A quick look on how I've created a simple Discord bot to manage an AzerothCore server with no extra effort, plug and play.

Published on May 28, 2020

A few months ago I’ve tried to make a new private WOTLK server, the idea was simple, manage everything through a Discord bot for ease of use and accessibility, sadly, we didn’t gather enough players to keep the server going, so I’ve decided to release the source code so everyone using AzerothCore could benefit from it.

If you wish to see the full code, please refer to my repository here.


I’ll show you, in parts, how it was built. To get started, we must create a new git repository (you don’t need a remote), to do so create a new directory and type the following command:

yarn init

Awesome, now let’s add a few packages, we will be using discord.js for the bot framework, mysql to handle all the database related tasks and dotenv to keep our credentials secret.

yarn add discord.js mysql dotenv

You also may want a linter, in that case use:

yarn add -D eslint

Great, time to get to work! Create a new file named index.js at the root of your project.

Fill this file with the following data:

// index.js

// importing dotenv

// package imports
const fs = require('fs')
const Discord = require('discord.js')

// setting the command prefix
const prefix = process.env.PREFIX || '!'
// bot initialization
const client = new Discord.Client()
// commands handler
client.commands = new Discord.Collection()

// searches the commands dir for `.js` files
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'))

// for each command found, import and register it
for (const file of commandFiles) {
  const command = require(`./commands/${file}`)
  client.commands.set(, command)

// whenever the bot is ready display a console message
client.once('ready', () => {
  console.log('Jeeves ready for duty!')

// this is where the real code lays
client.on('message', message => { /* code stripped for readiness purposes */ })

// login using our credentials

Now that the base code is done (aside from the stripped part) we can create commands, make a new folder called commands at the root directory of your project.

Creating a command:

// commands/help.js

// load secrets

// prefix once again
const prefix = process.env.PREFIX

module.exports = {
  // command name
  name: 'help',
  // command description
  description: 'List all of my commands or info about a specific command.',
  // command aliases
  aliases: ['commands'],
  // command cooldown
  cooldown: 1,
  execute(message, args) {
    // your code goes here

You get the point, so let’s dissect one of the more useful commands like the registration for example. For this example I’ll include the full snippet, but do remember that the source code is on Github, in case you wish to check it out later…

// commands/join.js

// import stuff
const mysql = require('mysql')
const crypto = require('crypto')

// create a new connection with your database
const connection = mysql.createConnection(`mysql://${process.env.MYSQL_USER}:${process.env.MYSQL_PASSWORD}@${process.env.MYSQL_HOST}/acore_auth`)

module.exports = {
  name: 'join',
  description: 'Command used to create an account into the world server.',
  aliases: ['signup', 'register', 'login'],
  usage: '<usernane> <password>',
  cooldown: 30,
  execute (message, args) {
    // fails if the user doesn't provide arguments
    if (!args.length) return message.reply('Missing arguments, type `!help join` for more info.')
    // store both given username and password
    const username = args[0]
    const password = args[1]

    // basic password checks
    if (!username || !password) return
    if (username.length <= 3) return
    if (password.length <= 6) return

    // hashing function to encrypt your password to be stored in the database
    const toPassword = (username, password) => {
      const hash = crypto.createHash('sha1')
      const data = hash.update(`${username.toUpperCase()}:${password.toUpperCase()}`, 'utf-8')
      return data.digest('hex').toUpperCase()

    // checks if the account already exists
    connection.query('select exists(select id from account where reg_mail = ?)', [], (error, results, fields) => {
      // if mysql couldn't connect or anything, display an error
      if (error) return message.reply('An error occured.')

      // if everything checks out then insert the values into the database
      if (Object.values(results[0])[0] === 0) {
        connection.query('insert into account (username, sha_pass_hash, reg_mail) values (?, ?, ?)', [username, toPassword(username, password),], (error, results, fields) => {
          if (error) {
            return message.reply('Syntax error, please check your input arguments.')
          } else { message.reply('Account created, you may login now.') }
      } else {
        message.reply('You already have an account!')

You should probably have an idea of what’s going on by now, in the next section we will be looking on how to setup and deploy this project.


In order to use this bot you will need to do some setup on Discord first, follow along:

  1. Login on Discord.
  2. Head over to the Developer Portal.
  3. Create a new application.
  4. Click the “Bot” tab and create a new bot.
  5. Save the token somewhere safe, you will need it later.
  6. Click the “OAuth2” tab and copy the client ID.
  7. Head over to to add your bot to a server.
  8. Done.

Feel free to manage the bot’s profile picture, description and the server role.

Since the repo provides a Dockerfile and heroku.yml configurations you can pretty much automatically deploy to Heroku.

In case you want to deploy somewhere else, modify Dockerfile and add the CMD line like the block below, else your bot won’t start.

FROM node:latest
COPY . /app
RUN yarn install
CMD yarn start

There are plenty of good hosts out there but if you want a cheap and performant option, check out Digital Ocean, use this link to get $100 in credit.


Deployment methods will be different for each platform, if you are using Heroku, just clone the repository, create a new project and push your local branch.

# login
heroku login
# create a new app
heroku create
# update stack to container
heroku set stack:container
# push to remote
git push heroku master

Finally, add the required environment variables, you can use a .env file or configure them within the settings page if you are deploying to Heroku.


Atfer setting that your bot should be online within a few minutes.


Even though I didn’t succeed on my server I sincerely hope that you do on yours. Feel free to open an issue/pull request if you wish to have more features added.

Thanks for reading!


Marlos Pomin
Full Stack Developer & Retoucher based in Brazil, also a casual pentester.