Skip to content

Creating a Bot

This guide walks through the code inside src/init.luau that create_app generates for you, explaining what each part does and why.

local discord = require("@self/../luau_packages/discord")
local classes = require("@self/../luau_packages/classes")
local builders = require("@self/../luau_packages/builders")
local env = require("@self/../.env")
  • discord - the top-level package, exposes discord.bot
  • classes - Luau types for Discord objects such as classes.Message, classes.Guild
  • builders - builder objects for constructing API payloads (intents, messages, embeds, etc.)
  • .env - your local environment file containing DISCORD_BOT_TOKEN

Intents tell Discord which gateway events to send your bot. You must request only what you need.

local DISCORD_BOT_INTENTS = builders.intents
.new({
"Guilds",
"GuildMessages",
"MessageContent",
})
:build()

builders.intents.new() accepts a list of intent names and :build() converts them into the bitfield integer that the Discord gateway expects.

local bot = discord.bot.new({
token = env.DISCORD_BOT_TOKEN,
intents = DISCORD_BOT_INTENTS,
reconnect = true,
})
OptionTypeDescription
tokenstringYour bot token
intentsnumberThe bitfield produced by builders.intents
reconnectboolean?Automatically reconnect on disconnect
logLevelstring?Log verbosity - "Debug", "Info", "Warn", "Error"

Events are exposed as emitters on the bot object. Call :listen() to register a persistent handler, or :listenOnce() for a one-shot handler.

bot.onMessage:listen(function(message: classes.Message)
print(`Message from '{message.author.globalName}': '{message.content}'`)
end)
bot.onAllShardsReady:listenOnce(function()
print(`Bot '{bot.user.username}' is online!`)
end)

onAllShardsReady fires once all shards have connected and the bot.user and bot.application properties are populated. Use this event as the signal that the bot is fully ready.

bot:connectAsync():await()

connectAsync() queries the Discord gateway, opens the WebSocket connection, and begins dispatching events. Calling :await() on it keeps the main thread alive for the lifetime of the bot.

Full script
local discord = require("@self/../luau_packages/discord")
local classes = require("@self/../luau_packages/classes")
local builders = require("@self/../luau_packages/builders")
local env = require("@self/../.env")
local DISCORD_BOT_INTENTS = builders.intents
.new({
"Guilds",
"GuildMessages",
"MessageContent",
})
:build()
local bot = discord.bot.new({
token = env.DISCORD_BOT_TOKEN,
intents = DISCORD_BOT_INTENTS,
reconnect = true,
})
bot.onMessage:listen(function(message: classes.Message)
print(`Message from '{message.author.globalName}': '{message.content}'`)
end)
bot.onAllShardsReady:listenOnce(function()
print(`Bot '{bot.user.username}' is online!`)
end)
bot:connectAsync():await()
  • Bot - the discord.bot class, gateway connection and event emitters
  • Intents builder - builders.intents, constructs the gateway intent bitfield
  • Message class - classes.Message, the object passed to onMessage handlers
  • Futures - the FutureLike async primitive returned by connectAsync and other async calls