Patches System
Modify Discord's JavaScript source code at runtime using Plexcord's regex-based patches system. Learn find, replacement, match, replace, and advanced patterns.
Patches System
Patches are Plexcord's most powerful feature. They allow you to modify Discord's JavaScript code at runtime, changing behavior that would otherwise be impossible to alter.
Patches are powerful but fragile. Discord updates can break them without warning. Always test patches after Discord updates and handle failures gracefully.
How Patches Work
Plexcord intercepts Discord's Webpack module loading process. Before a module is executed, active patches are applied, replacing matching code with your replacement code.
Discord Plexcord
───────── ───────────
Webpack Patch applied:
module.js ──────────► match regex → replace → modified module.js
│
▼
Executed by DiscordThe entire process happens synchronously before the module runs, so your replacement is always in effect.
Basic Patch Structure
import definePlugin from "@utils/types";
export default definePlugin({
name: "MyPatch",
description: "Modifies a Discord function",
authors: [{ name: "You", id: 0n }],
patches: [
{
// find: String or regex that identifies the MODULE to patch
// Must uniquely match the module containing what you want to change
find: "someUniqueStringInTheModule",
replacement: {
// match: Regex that matches the SPECIFIC CODE to replace within the module
match: /functionToModify\((\w+)\)/,
// replace: What to replace the match with
// $1, $2... are regex capture groups
replace: "functionToModify($1, extraArg)"
}
}
]
});The find Property
find identifies which module to patch. It must be unique; if it matches multiple modules, you get unexpected results.
// String find: looks for this exact string in module source
find: "MessageStore.getMessages",
// Regex find: more precise matching
find: /exports\.sendMessage\s*=\s*function/How to find the right value
- Open Discord DevTools (
Ctrl+Shift+I) - Go to the Sources tab
- Use
Ctrl+Shift+Fto search across all sources - Search for a unique string near the code you want to patch
- Make sure only one module contains that string
The replacement Property
replacement specifies what to replace and what to replace it with.
Simple replacement
replacement: {
match: /\.premium/g, // Match all occurrences
replace: ".superPremium" // Replace with this
}Capture group replacement
replacement: {
// Capture the argument list
match: /checkPermissions\((\w+),\s*(\w+)\)/,
// Re-use capture groups with $1, $2
replace: "checkPermissions($1, $2, true /* override */)"
}Multiple replacements in one patch
patches: [
{
find: "someModule",
replacement: [
// First replacement
{
match: /condition1/,
replace: "newCondition1"
},
// Second replacement (on the same module)
{
match: /condition2/,
replace: "newCondition2"
}
]
}
]Real-World Examples
Example 1: Bypass a Rate Limit Check
patches: [
{
find: "MESSAGE_SEND_BEFORE_UNLOAD",
replacement: {
match: /if\s*\(\w+\.cooldown\s*&&/,
replace: "if (false && " // Always skip the cooldown check
}
}
]Example 2: Inject a Custom Property
patches: [
{
find: "renderMessageContent",
replacement: {
// Match function return, capture existing render
match: /return\s+(renderMessageContent\([^)]+\))/,
// Wrap with our decorator
replace: "return myPlugin.wrapContent($1)"
}
}
]Example 3: Replace a Function Entirely
patches: [
{
find: "calculateBadgeCount",
replacement: {
match: /function calculateBadgeCount\([^)]*\)\s*\{[^}]+\}/,
replace: "function calculateBadgeCount(userId) { return 0; }"
}
}
]Patch Options
predicate: Conditional Patches
Apply a patch only when a condition is met:
patches: [
{
find: "someModule",
predicate: () => settings.store.enablePatch, // Only patch if setting is on
replacement: {
match: /someCode/,
replace: "newCode"
}
}
]all: Patch All Matching Modules
When multiple modules contain the same find string and you want to patch all of them:
patches: [
{
find: "commonPatternInManyModules",
all: true, // Apply to every matching module
replacement: {
match: /regex/,
replace: "replacement"
}
}
]noWarn: Suppress Patch Failure Warnings
By default, Plexcord logs a warning if a patch fails (e.g., after a Discord update). Suppress it for optional patches:
patches: [
{
find: "maybeExistFeature",
noWarn: true, // Don't warn if this doesn't match
replacement: {
match: /optionalCode/,
replace: "enhancedCode"
}
}
]Injecting Plugin Functions
Often you want to call your own plugin code from inside Discord's patched code. Use self from the Webpack context:
import { addContextMenuPatch } from "@api/ContextMenu";
export default definePlugin({
name: "InjectExample",
description: "Injects plugin function into Discord code",
authors: [{ name: "You", id: 0n }],
myCustomFunction(arg: string) {
console.log("Called from patch with:", arg);
},
patches: [
{
find: "someModule",
replacement: {
match: /doSomething\((\w+)\)/,
// Access plugin via Plexcord.Plugins.plugins.PluginName
replace: (_, arg) =>
`(Vencord.Plugins.plugins.InjectExample.myCustomFunction(${arg}), doSomething(${arg}))`
}
}
]
});Debugging Patches
Check if your patch applied
// In DevTools console:
// Look for your module and verify the replacement happened
Vencord.Webpack.findAll(m => m.toString?.().includes("yourReplacedCode"))Failed patch indicators
In the DevTools console, failed patches show as:
[Plexcord] Patch "YourPluginName > someModule" had no effectThis means the match regex didn't find anything in the module. After a Discord update, re-inspect the module source and update your regex.
Patch Safety Tips
- Be as specific as possible with your
matchregex - Capture and re-use code you don't want to remove (using
$1,$2, etc.) - Use
noWarn: truefor optional patches that may not always exist - Test after every Discord update
- Keep patches small: the smaller the change, the less likely it breaks