Plugin Structure
Deep dive into the definePlugin interface. Learn every property, lifecycle method, and pattern used in Plexcord plugins.
Plugin Structure
Every Plexcord plugin is built around a single function: definePlugin(). This guide explains every property you can use.
The definePlugin Signature
import definePlugin, { OptionType } from "@utils/types";
export default definePlugin({
// --- Required ---
name: "MyPlugin",
description: "What this plugin does",
authors: [{ name: "You", id: 0n }],
// --- Optional Lifecycle ---
start() {},
stop() {},
startAt: StartAt.DOMContentLoaded,
// --- Optional Features ---
settings: undefined, // Plugin settings definition
patches: [], // Code patches
commands: [], // Slash commands
flux: {}, // Flux event listeners
// --- Optional Metadata ---
dependencies: [], // Other plugins this requires
required: false, // Can't be disabled
enabledByDefault: false,
tags: [],
});Required Properties
name
The unique identifier and display name of your plugin.
name: "Bettertyping",- Must be unique across all plugins
- Shown in the plugins list in Discord settings
- Used for logging and debugging
- PascalCase is the convention
description
A short description shown below the plugin name in settings.
description: "Improves the typing indicator in DMs",Keep it under 100 characters. It appears directly in the settings UI.
authors
An array of author objects. Each author has a name and optional Discord id.
authors: [
{
name: "YourName",
id: 123456789012345678n // Discord user ID as BigInt
},
{
name: "Collaborator",
id: 987654321098765432n
}
],The id is a BigInt (notice the n suffix). You can find your Discord ID by enabling Developer Mode in Discord settings, then right-clicking your name.
Lifecycle Methods
start()
Called when the plugin is enabled or when Discord loads with the plugin already enabled.
start() {
// Set up intervals, event listeners, DOM manipulation
this.interval = setInterval(() => {
console.log("Tick");
}, 5000);
},Store any resources (timers, listeners) you create in start() so you can clean them up in stop().
stop()
Called when the plugin is disabled. Always clean up side effects here.
stop() {
// Clean up everything created in start()
clearInterval(this.interval);
document.removeEventListener("click", this.handler);
},If you don't clean up properly, effects from your plugin will persist even after it's disabled.
startAt
Controls when in the Discord startup sequence your plugin initializes.
import { StartAt } from "@utils/types";
startAt: StartAt.DOMContentLoaded, // Default - after DOM is ready
startAt: StartAt.Init, // Very early, minimal Discord loaded
startAt: StartAt.WebpackReady, // After Webpack modules are available| Value | When it runs | Use when |
|---|---|---|
StartAt.Init | Very early startup | Modifying core internals |
StartAt.DOMContentLoaded | DOM is ready (default) | Most plugins |
StartAt.WebpackReady | Webpack modules loaded | Accessing Discord modules |
Plugin Settings
Define a settings panel using the settings property. See Adding Settings for full details.
import { definePluginSettings } from "@api/Settings";
import { OptionType } from "@utils/types";
const settings = definePluginSettings({
showBadge: {
type: OptionType.BOOLEAN,
description: "Show a badge next to the username",
default: true
}
});
export default definePlugin({
name: "MyPlugin",
description: "...",
authors: [{ name: "You", id: 0n }],
settings,
start() {
if (settings.store.showBadge) {
// Badge logic
}
}
});Patches
Patches modify Discord's source code at runtime using regex replacement. They're the most powerful plugin feature.
patches: [
{
find: "showCooldownTooltip",
replacement: {
match: /\.cooldown\b/,
replace: ".cooldown && false" // Disables cooldown check
}
}
],See Patches System for complete documentation.
Commands
Register Discord slash commands:
commands: [
{
name: "ping",
description: "Check if Plexcord is responding",
execute() {
return { content: "Pong!" };
}
}
],See Commands System for complete documentation.
Flux Listeners
Subscribe to Discord's internal event system:
flux: {
MESSAGE_CREATE({ message }) {
console.log("New message:", message.content);
},
PRESENCE_UPDATE({ user }) {
console.log("User came online:", user.username);
}
},See Flux Events for all available events.
Plugin Dependencies
Declare other plugins that yours depends on:
dependencies: ["MessageLogger", "UserTags"],If a dependency is disabled, Plexcord will warn the user and may disable your plugin.
Other Metadata
// This plugin cannot be turned off by the user
required: true,
// Enabled by default for all users
enabledByDefault: true,
// Tags help users find the plugin via search
tags: ["utility", "messages", "formatting"],Complete Example
Here's a full plugin that demonstrates multiple features:
import definePlugin, { OptionType } from "@utils/types";
import { definePluginSettings } from "@api/Settings";
import { Logger } from "@utils/Logger";
const logger = new Logger("ExamplePlugin", "#FFD700");
const settings = definePluginSettings({
enabled: {
type: OptionType.BOOLEAN,
description: "Enable the main feature",
default: true
},
prefix: {
type: OptionType.STRING,
description: "Prefix added to log messages",
default: "[Example]"
}
});
export default definePlugin({
name: "ExamplePlugin",
description: "Demonstrates all plugin structure features",
authors: [{ name: "Dev", id: 123456789n }],
settings,
tags: ["example", "demo"],
start() {
logger.info("Plugin started with settings:", settings.store);
},
stop() {
logger.info("Plugin stopped.");
},
flux: {
MESSAGE_CREATE({ message }) {
if (settings.store.enabled) {
logger.info(settings.store.prefix, "Message:", message.content);
}
}
}
});