Skip to content

App Setup

Overview

An application is the Discord identity that owns commands, permissions, and a bot user. This page adapts the Discord.js App Setup topic to discord.go. The Portal steps are language-independent; the Go code below proves that the resulting bot token can authenticate and receive READY.

Architecture

The Developer Portal stores application metadata and bot configuration. Discord issues a bot token for the Gateway and REST APIs. bot.New keeps that token private and creates the two clients used by the high-level API. OnReady runs after Discord accepts the token and sends the initial Gateway state.

Prerequisites

  • A Discord account allowed to create applications.
  • Go 1.26.4 or newer.
  • A shell with DISCORD_TOKEN available.
  • A test guild for the later Adding Your App step.

Quick Start

In the Developer Portal, choose New Application, open Bot, choose Reset Token only when necessary, and copy the new token to a secret store. Enable the Guilds intent in the code below. Save it as main.go in a Go module and run it:

bash
export DISCORD_TOKEN='replace-with-a-bot-token'
go mod init example.com/app-setup
go mod edit -replace discord.go=/path/to/discord.go
go get discord.go
go run .
go
package main

import (
	"log"
	"os"

	"github.com/discord-go/discord.go/bot"
	"github.com/discord-go/discord.go/intents"
)

func main() {
	token := os.Getenv("DISCORD_TOKEN")
	if token == "" {
		log.Fatal("DISCORD_TOKEN is required")
	}

	b := bot.New(token, bot.WithIntents(intents.Guilds))
	b.OnReady(func(ctx *bot.ReadyContext) {
		log.Printf("authenticated as %s (application ID %s)", ctx.User.Username, ctx.User.ID)
	})
	b.OnError(func(err error) {
		log.Printf("discord.go error: %v", err)
	})
	if err := b.Run(); err != nil {
		log.Fatal(err)
	}
}

Creating/Using

  1. Create an application and record its application ID for later REST work.
  2. Create a bot user from the Bot page.
  3. Enable only the intents required by the planned features. Guilds is enough for the program above.
  4. Never paste the token into source, a public issue, or a command that will be stored in shell history.
  5. Use OAuth2 installation after the bot exists; the token alone does not install the application in a guild.

The code does not need the application ID for Gateway startup. b.AppID() becomes available after READY when code needs it at runtime.

Common Patterns

  • Make DISCORD_TOKEN mandatory and fail closed.
  • Configure privileged intents in both the Portal and bot.WithIntents.
  • Use bot.WithErrorHandler or OnError to capture startup and handler failures.
  • Use a dedicated test bot so development commands cannot affect production.

Best Practices

  • Reset a leaked token immediately in the Portal; changing an environment variable is not enough.
  • Treat the application ID as public metadata but the bot token as a credential.
  • Start with Guilds; add MessageContent only when content inspection is unavoidable.
  • Give the bot the smallest guild permissions required by its commands.

Common Mistakes

Incorrect

go
b := bot.New("YOUR_BOT_TOKEN")

Correct

go
token := os.Getenv("DISCORD_TOKEN")
if token == "" {
	log.Fatal("DISCORD_TOKEN is required")
}
b := bot.New(token, bot.WithIntents(intents.Guilds))

Incorrect

go
bot.WithIntents(intents.Guilds | intents.MessageContent)

Correct

go
bot.WithIntents(intents.Guilds)

Add MessageContent only when the bot reads message text, and enable the privileged intent in the Portal first.

API Walkthrough

  • bot.New accepts the token and functional options.
  • bot.WithIntents(intents.Guilds) selects a non-privileged Gateway intent.
  • b.OnReady receives a typed ReadyContext with the authenticated user.
  • b.AppID() exposes the application/user ID after READY.
  • b.Run owns signal handling and graceful shutdown.
  • b.OnError receives Gateway, synchronization, and handler errors.

Examples

Released under the Apache License 2.0.