Incremental adoption
Move from a monolithic discord.js bot to Shardwire in stages: events-only sidecar, then actions, then multiple scoped app processes—without rewriting everything on day one.
Shardwire’s split is a process boundary, not a requirement to delete your existing bot on the first commit. This guide describes a default happy path used by teams that already ship a single discord.js codebase and want to adopt Shardwire safely.
Recommended end state
- Bot process:
createBotBridge()owns the Discord client, intents, and bridge server. It stays the only place that touchesDISCORD_TOKENfor gateway traffic. - App process(es):
connectBotBridge()overws://(local) orwss://(remote), each with a manifest, strict startup where appropriate, and a scoped secret when more than one consumer exists.
Read How Shardwire works if you have not internalized that split yet.
Stage A — Events-only sidecar (lowest risk)
Goal: Keep command handlers and most logic in the monolith; mirror one event stream to a separate process for logging, metrics, or experimentation.
- Add a small Node process that calls
connectBotBridge()with the same secret you already use for local tooling (or add a new scoped secret that only allowseventsyou need—see Capabilities & scoped secrets). - In the bot process, introduce
createBotBridge()alongside your existing client, or migrate gateway ownership in one controlled step (many teams replaceclient.login()flow withcreateBotBridge().ready()once secrets and ports are ready—see Bot bridge). - Subscribe only to read-only events first (for example
messageCreatewithout moderation actions on the app side).
Contract: Define a minimal manifest with only those events (and no actions if the app is read-only). Use defineShardwireApp and pass it to app.ready({ strict: true, manifest, botIntents }) so mismatched intents or subscriptions fail at startup instead of at runtime.
Exit: App process receives normalized payloads and you are comfortable with deployment (URLs, secrets, restarts).
Stage B — Actions on the app process
Goal: Move specific side effects (delete message, timeout member, follow-up to an interaction) into the app process while the bot process remains the Discord gateway host.
- Extend the manifest with the actions the app will call.
- Regenerate or adjust the bot
secretsentry usinggenerateSecretScope(or a slightly wider manualallowlist) so negotiation includes those actions. - Every action call should branch on
result.ok(App bridge).
Optional: set expectedScope in strict startup so a deployment mistake cannot silently grant more than the manifest implies.
Exit: One vertical slice (for example “automod delete + log”) runs through the bridge with typed results.
Stage C — Multiple app consumers
Goal: Separate teams or services (dashboard, moderation worker, analytics) each get their own secret and capability surface.
- Add multiple entries under
server.secretson the bot bridge (Bot bridge). - Give each app process its own secret value and manifest. Prefer narrow
allow.events/allow.actionsper secret (Capabilities & scoped secrets). - Use strict startup per app so each process validates its contract against negotiation.
Exit: Adding a new dashboard does not force widening the moderation worker’s secret.
What not to do in early stages
- Do not treat the manifest as a full application config file—it is only the app contract (Manifests).
- Do not register
app.onhandlers afterawait app.ready({ strict: true })and expect them to be covered by strict startup’s subscription snapshot; register handlers first, then callready.
Where to go next
- Manifests and Strict startup for contracts.
- Diagnostics and
formatShardwireDiagnosis(see reference) for readable reports in logs and CI. - Recipe pages under Guides for end-to-end shapes (moderation, interactions, analytics-only).