Building a Discord Bot with Deno and Harmony. A Step-by-Step Guide

by Pinta

11 min read

The world of online communities has evolved dramatically over the years, and Discord stands at the forefront of this transformation. Discord, a versatile communication platform, has become the go-to hub for gamers, hobbyists, professionals, and enthusiasts to connect, share, and collaborate. One of the key features that has contributed to Discord's widespread popularity is the ability to add custom bots, which can enhance server functionality, automate tasks, and create unique interactive experiences.

Creating your own Discord bot can seem like a daunting task, especially if you're new to programming or unfamiliar with the tools and technologies involved. However, fear not! In this comprehensive guide, we'll demystify the process and walk you through the steps to build a Discord bot from scratch, using two powerful tools: Deno and Harmony.

Feel free to contact me on this Discord server for help with this project along the way or even if you just want to reach out to like-minded developers.

Why Deno and Harmony?

You might wonder why we've chosen Deno and Harmony for this tutorial. Deno, a secure runtime for JavaScript and TypeScript, has gained rapid popularity within the developer community for its simplicity, security, and ease of use. It's a worthy successor to Node.js, offering a fresh perspective on server-side JavaScript development. Harmony, on the other hand, is a Discord API library specifically designed for Deno. It provides an intuitive and efficient way to interact with Discord's APIs, making it an excellent choice for bot development.

In this guide, we'll explore the synergistic power of Deno and Harmony, leveraging their capabilities to create a Discord bot that can perform a variety of tasks, respond to commands, and interact with your server's members. By the end of this journey, you'll not only have a functional Discord bot but also a deeper understanding of Deno and Harmony, setting you on a path to explore more advanced bot development on your own.

What to expect

This step-by-step guide is tailored for both beginners and experienced developers looking to dive into Discord bot development using Deno and Harmony. We'll start with the basics, ensuring that even if you're new to programming, you can follow along. For those with prior coding experience, you'll find opportunities to expand your knowledge and customize your bot's functionality to suit your server's unique needs.

So, whether you're a curious newcomer or a seasoned developer seeking a fresh approach to Discord bot creation, let's embark on this journey together. By the end of this guide, you'll have the skills and confidence to bring your own Discord bot ideas to life. Let's get started on building a Discord bot with Deno and Harmony that will elevate your server and engage your community in exciting new ways!

Initializing your project with Deno

Before we dive into creating our Discord bot with Deno and Harmony, let's set up our project environment. Deno makes this process straightforward:

  1. Install Deno: If you haven't already, you'll need to install Deno on your system. Visit this getting started guide for installation instructions specific to your platform.

  2. Create and navigate to the project directory:

    # Create and navigate to project directory.
    mkdir deno-discord-bot
    cd deno-discord-bot
    # Open project folder with Visual Studio Code. (or any editor)
    code .
    

Set up the basic files

In our project directory, we'll need a few essential files to get started:

  • mod.ts: This file will serve as the entry point for our bot's code. Using mod.ts is the suggested default entry point for deno.

  • deps.ts: Here, we'll manage our project dependencies, including Harmony.

  • .env: We'll use this file to store sensitive information like your bot's token securely.

You can create these files manually and later, we'll populate them with the necessary code and configurations to bring your Discord bot to life.

An image representing the folder structure opened in VS Code

With your project directory initialized and the basic files in place, you're ready to proceed to the next steps of building your Discord bot using Deno and Harmony.

So, let's continue our journey of creating a powerful Discord bot with Deno and Harmony!

Creating Your Discord Bot on the Developer Portal

To make your bot functional and interact with Discord servers, you'll need to create it on the Discord Developer Portal. Follow these steps to set up your bot:

  1. Access the Developer Portal: Visit the Discord Developer Portal and log in using your Discord account.

  2. Create a New Application: Click the "New Application" button to create a new project for your bot. Give your application a name, such as "My Deno Bot". read and agree to the terms and policies and click "Create". An image showing where to create a new application An image showing the pop-up you get when creating a new application

  3. Token: Navigate to "Bot" in the left sidebar. Under the "Token" section on the bot page you'll find your bot's token. This token is like a secret key that allows your bot to connect to Discord. Keep it confidential, and never share it publicly or commit it to a public repository. You might have to press "reset token" to get your first token and you can always reset this code and copy a new one if you accidentally lost it or made it public. An image showing where to get the bot token An image showing where to copy the bot token

  4. Add bot to server: Navigate to "OAuth2" in the sidebar and select "URL Generator" from the subsections, you can generate an OAuth2 URL to invite your bot to your Discord server. Select the "bot" scope, and any additional permissions your bot may need. Copy the generated URL and paste it into a new browser tab. Select the server where you want to add the Bot to and press Authorize. An image showing where to get URL for adding your bot to a server An image showing how it looks when you issue the URL to add the bot to a server Now that you have your bot set up on the Developer Portal, have its token and you added it to your server, you're ready to integrate it into your Deno and Harmony project.

Let's enter some code

First we add the bot token to our .env-file. This is just a raw text file that we never commit into a public repository.

.env

TOKEN=MTE0NzA5NzQ2OTYxMjczNjU3Mg.G4Ti1V.bWlLftQXN1RtXwhqS-tIPazHuy_P1RQFOv4sHM

Secondly we update the depts.ts-file, this is used to keep track of all our project dependencies. It makes it easy to manage versions and gives you a good overview of what is being used.

depts.ts

// This line is for turning your .env-file into environmental variables.
import "https://deno.land/std@0.200.0/dotenv/load.ts";
// The harmony package used to interact with the discord API.
export * from "https://deno.land/x/harmony@v2.9.0/mod.ts";

mod.ts

Lastly we update the mod.ts-file, this is the base program and main entry point of our bot.

// Import dependencies from depts. Client is a class provided by the
// Harmony library and Intents is an enum used to specify bot intentions
// and permissions.
import { Client, Intents } from "./deps.ts";

//Retrieve the bot token from the environmental variable.
const token: string = Deno.env.get("TOKEN") || "";

// This creates the bot class which extends the harmony class. Right now
// its basically just the bare minimum of what we need to fire up the bot.
class MyBot extends Client {
    constructor() {
        super();

        // Set up an event listener for the "ready" event. it will fire
        // when the bot is connected and ready to go.
        this.on("ready", () => {
            console.log("Ready!");
        });
    }
}

// Create an instance of the bot.
const bot = new MyBot();

// Connecting the bot to discord using the token, we don't need any
// Intents for our usecase at the moment.
bot.connect(token, Intents.None);

Start the bot for the first time

Now with the files prepared we should be able to start the bot with "deno run". Deno is secure by default and you need to allow it to, for example get environment access, read files or access the network. The flag -A (short for --allow-all) gives the runtime all permissions(!!) which can be nice for local development. If you ommit the -A flag the runtime will ask you for permission before accessing files or connecting to the internet, try it out.

Open a terminal in your project folder and issue the command.

deno run -A mod.ts

If everything worked as intended you should see the text "Ready!" in the console where you issued the deno run command and your bot should come online in your discord server. But...it doesnt do anything yet :)

Image showing a discord member list with the Deno bot online

Summary so far

Congratulations! You've successfully embarked on the journey of creating your Discord bot with Deno and Harmony. You've learned how to set up your project environment, retrieve the bot token, and connect your bot to Discord. The journey has just begun, and you now have a solid foundation to build upon.

In this guide so far, you've achieved the following:

  • Set up the project: You've learned how to initialize your project directory with Deno, ensuring you have the necessary files in place.

  • Created your bot: You've created a basic Discord bot class, set up an event listener for the "ready" event, and successfully connected your bot to Discord.

  • Added the bot to your server: You've added your bot to your Discord server, granting it access to interact with server members.

Now, it's time to take the next step and add more interactivity to your bot by creating a slash command.

Coding a slash command

In this section, we'll take your Discord bot to the next level by adding a "slash command" feature. Slash commands are user-initiated actions that allow server members to interact with your bot in a structured and intuitive way. We'll create a simple "/ping" command that responds with "Pong!" when invoked.

Updating .env

We update the .env-file with our server ID. We will add this command to this specific server, not globally. If you need help finding your server ID, check out this article.

TOKEN=MTE0NzA5NzQ2OTYxMjczNjU3Mg.G4Ti1V.bWlLftQXN1RtXwhqS-tIPazHuy_P1RQFOv4sHM
SERVER=661300542160633867

Creating command.ts

Now, let's create the commands.ts file that defines our slash command. In your project directory, create a new file named commands.ts with the following content.

import { SlashCommandPartial } from "./deps.ts";

export const commands: SlashCommandPartial[] = [
    {
        name: "ping",
        description: "Ping the bot.",
        options: [],
    },
];

This code defines a slash command named "ping" with a brief description.

Updating mod.ts

Let's update your mod.ts file to handle the slash command. Open your mod.ts file and make the following changes.

// Import dependencies from depts. Client is a class provided by the
// Harmony library and Intents is an enum used to specify bot intentions
// and permissions.
import { Client, Intents, Interaction } from "./deps.ts";
import { commands } from "./commands.ts";

// Retrieve the bot token and serverID from the environmental variable.
const token: string = Deno.env.get("TOKEN") || "";
const serverID: string = Deno.env.get("SERVER") || "";

// This creates the bot class which extends the harmony class. Right now
// its basically just the bare minimum of what we need to fire up the bot.
class MyBot extends Client {
    constructor(updateCommands = false) {
        super();

        // Set up an event listener for the "ready" event. it will fire
        // when the bot is connected and ready to go.
        this.on("ready", () => {
            console.log("Ready!");

            // Check if updateCommands is set to true.
            if (updateCommands) {
                this.updateCommands();
            }
        });

        // Set up an event listener for interacting with the bot.
        this.on("interactionCreate", (interaction: Interaction) => {

            // If the interaction is not a slash command we return early.
            if (!interaction.isApplicationCommand()) return;

            // Extract the data sent with the application interaction.
            const { data } = interaction;

            // If its our ping command, respond with Pong!!
            if (data.name === "ping") {
                interaction.respond({
                    content: "Pong!!",
                });
            }
        });
    }

    // This iterates over the commands and issues the create method for each.
    async updateCommands() {
        try {
            for (const cmd of commands) {
                await this.interactions.commands.create(cmd, serverID);
                console.log(`Created command ${cmd.name}!`);
            }
        } catch (err) {
            console.log(`Command creation failed: ${err}`);
        }
    }
}
// Create an instance of the bot. Set parameter to true if you
// want to create or update the commands.
const bot = new MyBot(false);

// Connecting the bot to discord using the token, we don't need any
// Intents for our usecase at the moment.
bot.connect(token, Intents.None);

To summarize what we changed:

  • Additional imports:
    • import { Interaction } from "./deps.ts";
    • import { commands } from "./commands.ts";
  • Additional environment variable:
    • const serverID: string = Deno.env.get("SERVER") || "";
  • Constructor parameter:
    • constructor(updateCommands = false) {
  • New event listener:
    • Event listener for the "interactionCreate" event.
  • Conditional check in "ready" Event:
    • Checks if updateCommands is true and calls this.updateCommands().
  • New method updateCommands:
    • A method that iterates over commands and issues the create method for each.
  • Changed instance creation:
    • When creating an instance of MyBot, a boolean parameter is passed to the constructor used to update commands.

Creating the slash application command

When you create commands you can register them globally or for a specific server(guild). Global commands can be useful if you have your bot across several servers and wants to share commands. Specific-scoped commands update instantly but globals might be delayed. Read more here.

Lets do it

We already prepared a snippet of code in mod.ts to update commands, the class method updateCommands(). So all we need to do is instantiate the bot with a true parameter.

const bot = new MyBot(true);

And now we just open a terminal in your project folder and issue the deno run command again.

deno run -A mod.ts

The console should say that the bot is Ready! and that the command was created.

A console window showing the output

Head over to your discord server and try the command out. Write /ping and it should pop up as a suggestion. If everything worked well the bot should reply to you with "Pong!!".

An image from discord showing the /ping interaction

Change the parameter back to false so it doesnt update the command every time you restart the program. You only need to run the update method when you make changes to the commands.ts file to modify or add commands.

Final Words

As we wrap up this guide on building a Discord bot with Deno and Harmony, it's essential to reflect on the journey you've embarked on and the endless possibilities that await you in the world of bot development.

You've taken your first steps in creating a bot that can engage, entertain, and assist your Discord community. You've learned how to set up your project environment, connect your bot to Discord, and even added a slash command feature. But this is just the beginning.

Discord bot development is a creative endeavor with no limits. You can expand your bot's functionality to include music playback, moderation tools, informative utilities, or even unique games. It's an opportunity to bring your ideas to life and make your server a more vibrant and interactive place.

So, whether you're building a bot for your gaming clan, your online community, or just for fun, embrace the possibilities, keep learning, and never stop experimenting. Your Discord bot has the potential to make a significant impact and bring joy to countless users.

Thank you for joining us on this adventure, and here's to the incredible bots you'll create in the future. Happy coding!

Feel free to contact me on this Discord server for help with this project or even if you just want to reach out to like-minded developers.