Skip to main content
A plugin is a bundle of JavaScript that Unbound loads, evaluates, and runs inside Discord. Plugins add functionality the base app doesn’t ship, using the Developer API: Metro to find Discord’s internals, storage for settings, and the patcher to change behavior.

The shape of a plugin

A plugin is an object with optional lifecycle hooks. Unbound calls start when the plugin is enabled and stop when it’s disabled. Set up everything the plugin does (patches, listeners, subscriptions) in start, and tear all of it down in stop.
Whatever you create in start, undo in stop. A disabled plugin should leave nothing running. Leftover patches and listeners are the most common source of bugs after a plugin is disabled.

How plugins are loaded

Unbound loads and evaluates every installed plugin’s bundle at startup, whether or not the plugin is enabled. For a disabled plugin, Unbound never calls start, but the bundle’s top-level code still runs. This means anything at the top level of your bundle runs for every user on every launch, even when your plugin is turned off.
Do not run Metro searches at the top level of your plugin. findByProps, findByName, and the other search functions walk the module registry. Running them at import time, for a plugin that may be disabled, slows down startup for every user.

Writing a fast plugin

Two techniques keep a plugin’s startup cost near zero until it’s enabled and used.

Defer module lookups with lazy

Pass the { lazy: true } search option to top-level Metro lookups. The search then runs the first time you access the result (inside start, or later inside a handler) instead of at import.

Split heavy work behind a dynamic import

Keep your bundle’s entry point small. Move code that pulls in many modules into separate files, and import() those files inside start. That code then loads only when the plugin runs.
Structure your plugin as a small entry point plus modules it loads on demand. At import time, the entry point should do almost nothing beyond declaring lazy handles and waiting for start.

Where to go next

Manifest

The metadata every addon ships and how it’s validated.

Patcher

Intercept and modify any function with the patcher.

Patching Components

Change what Discord’s components render.

Flux Stores

React to Discord’s internal events and stores.

Debugging

Tools for developing and inspecting your plugin.