Building Discord Bots Shouldn't Feel Like Wiring Everything Together — Meet Nexcord
If you've ever built a Discord bot with discord.js, you've probably ended up writing code that looks something like this:
- Register every command manually.
- Register every event manually.
- Create service instances yourself.
- Pass dependencies through constructors.
- Keep import lists up to date as the project grows.
None of these tasks are particularly difficult.
But after you've done them dozens of times, they start feeling more like maintenance than development.
After working on several Discord projects, I found myself wanting something closer to the experience of frameworks like NestJS or Angular, while still keeping everything I like about discord.js—its flexibility, performance, and ecosystem.
That's how Nexcord started.
What is Nexcord?
Nexcord is a decorator-driven, dependency-injection-powered framework built on top of discord.js.
Rather than spending time wiring your application together, you simply describe what each class is responsible for.
@Service()
export class GreetingService {
greet(name: string) {
return `Welcome ${name}!`;
}
}
@Listener()
export class MemberListener {
constructor(private readonly greeting: GreetingService) {}
@On('guildMemberAdd')
async execute(member: GuildMember) {
await member.send(
this.greeting.greet(member.user.username)
);
}
}
There's no need to manually create services.
No event registration to keep track of.
No growing bootstrap file that slowly turns into hundreds of lines.
Nexcord discovers your classes automatically, builds the dependency graph, and wires everything together for you.
Dependency Injection without the Boilerplate
Dependency Injection isn't a new idea.
What interested me was bringing the same experience to Discord bot development.
Every class decorated with one of Nexcord's decorators automatically becomes part of the dependency injection container.
@Service()
class QuoteService {}
@SlashCommand(...)
class QuoteCommand {
constructor(
private readonly quotes: QuoteService
) {}
}
If QuoteService depends on another service...
...and that service depends on another...
...Nexcord resolves the entire dependency graph automatically.
Each service is instantiated only once and shared across the application, so you don't have to think about lifecycle management.
Convention over Configuration
One thing that always bothered me in larger projects was maintaining registration files.
Every new command or listener meant adding another import somewhere.
Eventually those files became longer than the actual feature I was implementing.
Nexcord takes a different approach.
src/
├── commands/
├── events/
├── configs/
├── common/
When the application starts, these folders are scanned automatically.
Add a new command.
Run the bot.
That's it.
No extra registration step.
Guards for More Than Commands
Most Discord frameworks offer middleware, but it's usually tied to slash commands.
I wanted something that worked everywhere.
That's why Nexcord introduces Route Forwarding Guards.
A guard can target:
- individual listeners
- commands
- groups of handlers
- wildcard patterns
- regular expressions
- prefixes and suffixes
For example:
@Guard(
{ MemberListener },
"checkCooldown->MemberListener::onMessage"
)
If the guard returns false, execution stops before the listener ever runs.
The same mechanism works consistently for commands and events, so you don't need different middleware systems depending on what you're handling.
Shared Configuration that Understands Dependency Injection
Configuration is often more than static strings.
Sometimes generating a configuration value requires access to another service.
That's the reason I built @nexcord/config.
Instead of writing something like this during startup:
const prefix = prefixService.get();
you register the configuration once.
registerConfig(
"messages.welcome",
(prefix: PrefixService) =>
`Type ${prefix.get()}help`,
PrefixService
);
Nexcord automatically resolves PrefixService.
The value is computed once and becomes available everywhere through ConfigService.
For values that require the Discord client to already be connected, there's also registerConfigWait().
JSX for Discord Components
Anyone who's built more complex Discord UIs knows that component builders can become fairly verbose.
Buttons.
Embeds.
Select menus.
Modals.
Components V2.
All of them involve long builder chains that can quickly become difficult to read.
Nexcord includes @nexcord/tsx, a JSX runtime designed specifically for Discord components.
<button
id="confirm"
label="Confirm"
style="success"
action={ConfirmAction}
/>
This compiles directly into the appropriate discord.js builders.
There's no virtual DOM.
No rendering engine.
Just a cleaner, more expressive syntax for creating Discord components.
Built Around an Ecosystem
Nexcord is currently made up of three packages.
- @nexcord/core — decorators, dependency injection, automatic discovery, guards, and the framework runtime.
- @nexcord/config — dependency-injection-aware shared configuration.
- @nexcord/tsx — a JSX runtime for Discord components.
Each package can be used independently.
Together, they provide a more structured and enjoyable development experience.
Why I Built It
Nexcord wasn't created because Discord needed another library.
discord.js already does an excellent job.
The motivation was different.
I wanted to spend less time wiring projects together and more time building actual features.
Less repetitive setup.
Cleaner architecture.
Automatic discovery.
Dependency injection.
Better organization as projects grow.
Nexcord doesn't try to replace discord.js.
It simply aims to provide a higher-level development experience on top of it.
Current Status
Nexcord is currently in beta.
The core architecture is already in place, but there are still APIs I'm refining before the 1.0 release.
This stage is where feedback matters the most.
Many of the decisions that will shape the stable release are still open to improvement, so hearing how other developers approach Discord bot development is incredibly valuable.
If you're interested in building larger Discord bots with a more structured architecture, I'd genuinely love to hear your thoughts.
Thanks for reading.
Top comments (0)