RepoPilotOpen in app →

bwmarrin/discordgo

(Golang) Go bindings for Discord

Healthy

Healthy across the board

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 3mo ago
  • 53+ active contributors
  • Distributed ownership (top contributor 21% of recent commits)
Show all 6 evidence items →
  • BSD-3-Clause licensed
  • CI configured
  • No test directory detected

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/bwmarrin/discordgo)](https://repopilot.app/r/bwmarrin/discordgo)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/bwmarrin/discordgo on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: bwmarrin/discordgo

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/bwmarrin/discordgo shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 3mo ago
  • 53+ active contributors
  • Distributed ownership (top contributor 21% of recent commits)
  • BSD-3-Clause licensed
  • CI configured
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live bwmarrin/discordgo repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/bwmarrin/discordgo.

What it runs against: a local clone of bwmarrin/discordgo — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in bwmarrin/discordgo | Confirms the artifact applies here, not a fork | | 2 | License is still BSD-3-Clause | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 112 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>bwmarrin/discordgo</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of bwmarrin/discordgo. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/bwmarrin/discordgo.git
#   cd discordgo
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of bwmarrin/discordgo and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "bwmarrin/discordgo(\\.git)?\\b" \\
  && ok "origin remote is bwmarrin/discordgo" \\
  || miss "origin remote is not bwmarrin/discordgo (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(BSD-3-Clause)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"BSD-3-Clause\"" package.json 2>/dev/null) \\
  && ok "license is BSD-3-Clause" \\
  || miss "license drift — was BSD-3-Clause at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "discord.go" \\
  && ok "discord.go" \\
  || miss "missing critical file: discord.go"
test -f "structs.go" \\
  && ok "structs.go" \\
  || miss "missing critical file: structs.go"
test -f "restapi.go" \\
  && ok "restapi.go" \\
  || miss "missing critical file: restapi.go"
test -f "wsapi.go" \\
  && ok "wsapi.go" \\
  || miss "missing critical file: wsapi.go"
test -f "event.go" \\
  && ok "event.go" \\
  || miss "missing critical file: event.go"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 112 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~82d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/bwmarrin/discordgo"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

DiscordGo is a Go library providing low-level bindings to the Discord API, enabling developers to build bots and applications that interact with Discord's REST endpoints, WebSocket gateway, and voice channels. It offers nearly complete coverage of Discord's API including slash commands, components, modals, auto-moderation, and scheduled events. Flat monolithic structure: core bindings in discord.go, discord_test.go, endpoints.go; event handling scattered across event.go, eventhandlers.go, events.go; UI components in components.go. Examples/ folder contains 15 self-contained bot implementations (pingpong, modals, components, voice, etc.) demonstrating different feature areas. Documentation lives in docs/ with Markdown guides.

👥Who it's for

Go developers building Discord bots and integrations who need programmatic access to Discord's chat, voice, and user management features without wrestling with raw HTTP calls and WebSocket protocol details.

🌱Maturity & risk

Actively maintained and production-ready. The project has comprehensive CI/CD via GitHub Actions (.github/workflows/ci.yml), well-structured examples across 15+ use cases (examples/ directory), and Go reference documentation. Regular updates indicate ongoing Discord API compatibility work, though the README notes the Discord API itself is unfinished.

Single-maintainer repo (bwmarrin) creates sustainability risk. No visible dependency lock file in the main repo (though examples/linked_roles/go.sum exists), making supply-chain risk assessment difficult. Discord API is a moving target—breaking changes in Discord's API surface require reactive updates. Last activity visible in CI workflow and example structure suggests active maintenance, but typical for a wrapper library rather than explosive growth.

Active areas of work

Active feature parity work with Discord API—examples show recent additions like auto_moderation, linked_roles, scheduled_events, and modals. CI pipeline (ci.yml) is configured and running. The library tracks Discord's evolving feature set rather than major architectural refactors.

🚀Get running

go get github.com/bwmarrin/discordgo

Then import and create a client:

import "github.com/bwmarrin/discordgo"
discord, err := discordgo.New("Bot " + token)

See examples/ for runnable samples (e.g., cd examples/pingpong && go run main.go).

Daily commands: No development server to run. This is a library. To test: go test ./... (implied by ci.yml). To explore: pick an example like examples/pingpong/main.go, set a DISCORD_TOKEN env var, and go run main.go. Voice examples (airhorn) require ffmpeg and a valid bot in a voice channel.

🗺️Map of the codebase

  • discord.go — Core Session struct and connection lifecycle management; every contributor must understand the primary entry point and gateway connection handling.
  • structs.go — Data model definitions for all Discord API objects (Guild, User, Message, etc.); essential reference for understanding data shapes across the codebase.
  • restapi.go — REST API client implementation and request routing; critical for understanding how all HTTP endpoints are called and responses handled.
  • wsapi.go — WebSocket gateway implementation and event routing; core to real-time message delivery and connection lifecycle.
  • event.go — Event handler registration and dispatch system; required reading for understanding how Discord events flow through the library.
  • interactions.go — Slash commands, buttons, and modal interactions implementation; crucial for modern Discord bot development patterns.
  • voice.go — Voice connection and audio streaming implementation; load-bearing for voice channel features.

🛠️How to make changes

Add a new REST API endpoint

  1. Define the endpoint URL in endpoints.go following the pattern EndpointGuild{ID}Channel{ID} (endpoints.go)
  2. Add a public method on Session struct in restapi.go (e.g., ChannelMessageSend) that builds the request, handles rate limiting, and returns the parsed response (restapi.go)
  3. Define response/request structs in structs.go if new data types are needed (structs.go)
  4. Write tests in restapi_test.go covering success and error cases (restapi_test.go)

Add a new Discord event handler

  1. Define the event struct in events.go (e.g., MessageCreate with relevant fields from Discord API docs) (events.go)
  2. Add a handler function type stub in eventhandlers.go (func(s *Session, m *MessageCreate)) (eventhandlers.go)
  3. Register the handler in event.go's AddHandler method with the correct event name string (event.go)
  4. Add unmarshaling logic in wsapi.go's event switch statement to parse the gateway payload (wsapi.go)
  5. Dispatch the event by calling handleEvent in event.go after unmarshaling (event.go)

Add a new interaction type (slash command, button, modal)

  1. Define struct in structs.go for the interaction data (e.g., SlashCommandData with options) (structs.go)
  2. Add builder method in interactions.go or components.go to make construction ergonomic (interactions.go)
  3. Add handling in event.go's InteractionCreate event dispatch to route by interaction type (event.go)
  4. Implement InteractionRespond method in restapi.go to send responses back to Discord (restapi.go)
  5. Create an example in examples/ directory showing registration and response flow (examples/slash_commands/main.go)

Extend state caching for a new entity type

  1. Add a new map field to State struct in state.go (e.g., map[string]*User for users) (state.go)
  2. Add Get/Set methods in state.go with locking to safely access the cache (state.go)
  3. Hook into relevant event handlers in wsapi.go to update cache on GuildCreate, UserUpdate, etc. (wsapi.go)
  4. Write tests in state_test.go (if exists) or discord_test.go to verify cache correctness (discord_test.go)

🔧Why these technologies

  • Go (goroutines + channels) — Enables concurrent event handling, WebSocket heartbeating, and REST request queueing with minimal overhead; natural fit for I/O-bound Discord API work
  • gorilla/websocket — Well-maintained WebSocket library with proper frame handling and connection lifecycle management required for Discord gateway stability
  • net/http (standard library) — Sufficient for Discord's REST API; avoids external dependencies for HTTP client functionality
  • sync.RWMutex for state caching — Prevents race conditions in concurrent event handlers while allowing multiple readers to avoid lock contention

⚖️Trade-offs already made

  • Optional in-memory state cache (state.go) rather than always caching

    • Why: Users may want to use external caches or don't need local state; adding it as opt-in keeps the library lightweight
    • Consequence: Developer must manually enable State on Session; guild/channel/user lookups will miss if cache disabled
  • Synchronous REST methods that return results rather than event-driven responses

    • Why: Simpler API surface and easier error handling than forcing async patterns; matches standard Go conventions
    • Consequence: Caller must manage concurrency; no built-in request batching or pipelining
  • *Generic handler registration (func(s Session, event interface{})) rather than type-safe subscriptions

    • Why: Maximal flexibility; handlers can switch on event type at runtime
    • Consequence: No compile-time checking; requires developers to assert types manually in some cases
  • Rate limiter implemented per-Session rather than global or distributed

    • Why: Simpler; works for single-bot deployments without external state
    • Consequence: Multi-bot or distributed scenarios may need custom rate limiter wrapper

🚫Non-goals (don't propose these)

  • Does not provide voice encoding/decoding (audio processing delegated to external libraries like dca)
  • Does not handle bot sharding natively (developers must run separate Session instances and coordinate state)
  • Not a command framework (library only provides event dispatch; use discordgo-cmds or other frameworks for convenience)
  • Does not cache Discord API responses permanently (in-memory cache only; no persistent storage layer)

🪤Traps & gotchas

No built-in rate limiting—Discord enforces strict rate limits; high-volume bots need external backpressure logic. Voice support is skeleton-level—see dgVoice companion repo for real audio; this library only handles gateway plumbing. Token in production—examples use plaintext tokens; production code must use environment variables or secret managers. Gateway reconnection is automatic but can mask issues—graceful degradation may hide transient bugs. Example dependencies vary—linked_roles example uses oauth2 and godotenv; others are self-contained.

🏗️Architecture

💡Concepts to learn

  • Discord Intent System (Gateway Intents) — Discordgo must respect Discord's intent model to receive events (GUILDS, MESSAGES, VOICE_STATES, etc.); misconfigured intents cause silent event loss.
  • WebSocket Gateway Protocol (opcodes and heartbeating) — Discordgo implements the Discord Gateway protocol: opcode dispatch for events, opcode heartbeat for keep-alive, opcode identify for authentication. Understanding this explains event.go and gateway reconnection logic.
  • REST Rate Limiting (429 Too Many Requests) — Discord enforces per-endpoint and per-guild rate limits; discordgo has no built-in backoff, leaving rate limit handling to the caller—critical for high-volume bots.
  • Slash Commands and Application Commands — Modern Discord bot interaction model (ApplicationCommand struct); replaces prefix-based parsing and is covered in examples/ but requires understanding Discord's command registration vs. handler registration flow.
  • OAuth2 Bot Authorization — Discordgo bots authenticate via bot tokens in the Authorization header; examples/linked_roles shows OAuth2 user flow for different auth patterns.
  • Message Components (Buttons, Select Menus, Modals) — Interactive UI elements defined in components.go; essential for modern bot UX beyond plain text messages, demonstrated in examples/components and examples/modals.
  • Voice Channel Audio Streaming (Opus codec) — Discord requires Opus-encoded audio; airhorn example and dgvoice companion show that discordgo handles only WebSocket signaling, not encoding—external tools (dca, ffmpeg) are needed.
  • diamondburned/arikawa — Alternative Go Discord library with different API design (more type-safe, context.Context support); allows comparing idioms.
  • bwmarrin/dgvoice — Official companion repo providing high-level voice streaming helpers that complement discordgo's WebSocket layer.
  • bwmarrin/dca — Standalone ffmpeg wrapper tool that pre-encodes audio to Opus format for use with discordgo voice channels.
  • discord-js/discord.js — JavaScript equivalent—same problem domain, different ecosystem; useful for understanding design trade-offs and feature parity.
  • Rapptz/discord.py — Python Discord library; the most mature Discord binding with extensive patterns that informed discordgo's API design.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for interactions.go and components.go

The repo has interactions_test.go and discord_test.go, but components.go (which handles Discord's interactive components like buttons, select menus, modals) lacks dedicated test coverage. Given the complexity of component validation and serialization, and that there are multiple examples using components (examples/components, examples/modals), adding tests for component marshaling/unmarshaling would catch regressions early and serve as reference implementations.

  • [ ] Create components_test.go with tests for ActionRow, Button, SelectMenu, and Modal struct marshaling
  • [ ] Add tests for component validation logic to ensure Discord API compatibility
  • [ ] Add tests for component option parsing and type checking (SelectMenuOptions, SelectDefaultValues, etc.)
  • [ ] Ensure test coverage aligns with the real-world examples in examples/components and examples/modals

Add missing endpoint and integration tests for AutoModeration and ScheduledEvents APIs

The repo has examples/auto_moderation and examples/scheduled_events with working implementations, but interactions_test.go and discord_test.go don't include tests for these API features. Given that AutoModeration and ScheduledEvents are newer Discord features referenced in the codebase, adding unit tests for their endpoints (likely in endpoints.go) would validate API contract compliance and prevent future breaking changes.

  • [ ] Add tests in discord_test.go for AutoModeration rule creation, listing, and deletion endpoints
  • [ ] Add tests for ScheduledEvent CRUD operations (Create, Read, Update, Delete)
  • [ ] Test parameter validation and error handling for both features
  • [ ] Cross-reference implementations against examples/auto_moderation/main.go and examples/scheduled_events/main.go

Add GitHub Actions workflow for example code validation and compilation

The repo has .github/workflows/ci.yml for main library testing, but there's no CI to validate that the 12+ examples in examples/ directory actually compile and run. This is critical because examples are the primary documentation for new users, and broken examples damage the library's reputation. A separate workflow could catch breaking changes that affect example code.

  • [ ] Create .github/workflows/examples.yml that runs 'go build' for each example directory
  • [ ] Add a step to validate go.mod dependencies in examples/linked_roles and examples/voice_receive (which have local go.mod files)
  • [ ] Configure the workflow to fail if any example fails to compile
  • [ ] Add comments in CONTRIBUTING.md pointing contributors to update examples when they make breaking API changes

🌿Good first issues

  • Add tests to discord_test.go for endpoints.go functions—currently test coverage is minimal (discord_test.go exists but likely incomplete). Pick a single endpoint like UserGet or ChannelMessageEdit and write table-driven tests.
  • Create an examples/slash_commands/main.go—the repo has components and modals examples but no dedicated slash command registration/handling example. This is a top Discord bot feature and would guide many users.
  • Document the event lifecycle in docs/GettingStarted.md—explain the flow from WebSocket message → event.go unmarshaling → eventhandlers.go dispatch → user callback. Currently only API client setup is documented.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • f43dd94 — fix(SelectMenu, TextInput): Add Required field and omitempty to TextInput.Label (#1672) (Tesohh)
  • 9f6aa81 — feat: implement FileUploadComponent (#1679) (DeathHound6)
  • 547840c — feat: Support new guild role member count endpoint (#1684) (MagnusHJensen)
  • 0dcdfb7 — Add missing message reaction remove emoji event (#1688) (MagnusHJensen)
  • 54ae40d — Use aead_aes256_gcm_rtpsize transport encryption for voice (#1677) (Richy-Z)
  • 22e5cd8 — feat(restapi): Add support for voice state API endpoints (#1671) (MagnusHJensen)
  • c144aa1 — fix(GuildMembers): populate GuildID for consistency with GuildMember (#1676) (bamo)
  • 800fe85 — feat(User): implement PrimaryGuild attribute (#1665) (MagnusHJensen)
  • 6418873 — feat(restapi)!: use new channel pins endpoints (#1666) (MagnusHJensen)
  • dd9332c — feat(restapi): retry on 500s, 503s, 504s as well as 502s (#1586) (patrickxia)

🔒Security observations

The DiscordGo codebase appears to be a well-maintained Discord API binding library with reasonable security practices. However, there are concerns regarding outdated dependencies and Go version requirements that should be addressed. The primary risks are: (1) Go 1.13 is significantly outdated and unsupported, (2) OAuth2 dependency version is stale and may lack recent security patches, and (3) Environment variable handling with godotenv requires careful configuration to prevent credential leakage. The codebase lacks explicit security documentation and vulnerability disclosure guidelines. No evidence of hardcoded secrets, SQL injection, or XSS vulnerabilities was found in the file structure analysis. Dependency updates and security documentation improvements would bring the score closer to 85+.

  • Medium · Outdated Go Version Requirement — examples/linked_roles/go.mod. The linked_roles example specifies 'go 1.13' which was released in September 2019 and is significantly outdated. Go 1.13 reached end-of-life and no longer receives security updates. This increases the risk of using vulnerable standard library versions. Fix: Update the Go version requirement to at least Go 1.19 or later (preferably the latest stable version). Update all other example modules that may have similar issues.
  • Medium · Outdated OAuth2 Dependency — examples/linked_roles/go.mod. The linked_roles example uses 'golang.org/x/oauth2 v0.3.0' which was released in November 2022. Newer versions (1.x+) are available and may contain security patches. Using outdated dependencies increases exposure to known vulnerabilities. Fix: Update golang.org/x/oauth2 to the latest available version. Run 'go get -u golang.org/x/oauth2' and test thoroughly before deployment.
  • Low · Potential Environment Variable Exposure — examples/linked_roles/go.mod, .gitignore. The linked_roles example includes 'github.com/joho/godotenv v1.4.0', which loads environment variables from .env files. If .env files containing secrets are accidentally committed or if the .gitignore is misconfigured, credentials could be exposed. Fix: Ensure .env and .env.local files are properly listed in .gitignore. Never commit credential files. Use environment variable secrets management in CI/CD pipelines instead of local .env files.
  • Low · Missing Security Headers Documentation — README.md, docs/GettingStarted.md. The codebase includes OAuth2 functionality but lacks explicit security guidance regarding token handling, storage, and transmission in the provided README snippet. Fix: Add security best practices documentation covering: secure token storage, HTTPS-only transmission, token rotation, and protection against CSRF attacks in OAuth2 flows.
  • Low · No Security Policy Defined — Repository root. No SECURITY.md or security policy file is visible in the repository structure, making it unclear how security vulnerabilities should be reported. Fix: Create a SECURITY.md file defining vulnerability disclosure policy and responsible disclosure procedures.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · bwmarrin/discordgo — RepoPilot