Skip to main content

Getting Started

In this article, you'll learn about the basics of necord, and how it integrates with NestJS!

tip

Many of the concepts seen with necord are designed to be used like other components in a NestJS project.
We recommend you to be familiar with the NestJS documentation, especially its overview section, before getting started.

The very first step is to install necord and its dependency, Discord.js

npm install necord discord.js
tip

You need to install Node.js v16.0.0 or newer to use Necord and Discord.js.

Module

Necord is a module like any others, and can be imported as such within your Nest application.

NestJS modules

Not sure what modules are? Catch up by reading about them in NestJS!

discord.module.ts
import { Module } from '@nestjs/common';
import { AppService } from './app.service';
import { IntentsBitField } from 'discord.js';

@Module({
imports: [
NecordModule.forRoot({
token: process.env.DISCORD_TOKEN,
intents: [IntentsBitField.Guilds],
development: [process.env.DISCORD_DEVELOPMENT_GUILD_ID]
})
],
providers: [AppService]
})
export class DiscordModule {}
info

Make sure to setup the correct intents required by your application!

The module arguments are an extension of discord.js ClientOptions, in addition to 3 necord options: token, prefix and development.

export interface NecordModuleOptions extends DiscordClientOptions {
token: string;
prefix?: string | (message: Message) => string | Promise<string>;
development?: Snowflake[] | false;
skipRegistration?: boolean;
}

Token

token is your Discord token: it is used to authenticate as your bot.

Prefix

If you are using TextCommand, you can specify the prefix here. It can be a string for a static prefix, or a function which returns a string based off the message being sent. If using a function, it can be asynchronous.

Development

As discord caches application commands for up to an hour, it is recommended to specify a development guild when doing development. If you do not specify a development guild, your commands and their arguments are likely to be outdated.

Warning

If you have commands using the guilds property, the global development argument will not overwrite it.

Skip Registration

If skipRegistration is true, necord would not automatically register your application commands with Discord. You would have to register the application commands manually.

Structure

As Necord follows the NestJS structure, the various discord components available must be imported as providers.

info

In this section of the guide, all of the code will be in the app.service.ts file, but for a real application you should separate them into their own components such as discord.update.ts and ping.command.ts.

app.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
// Your code here
}

Event handlers

Necord supports interacting with all discord events via the @On and @Once decorator.
While the best practice is to use the more specific decorators when possible, this is useful if you wish to use features Necord doesn't support via custom decorators, to interact with the raw requests, or to listen to all events using a decorator such as interactionCreate.

app.service.ts
import { Injectable, Logger } from '@nestjs/common';
import { Once, On, Context, ContextOf } from 'necord';

@Injectable()
export class AppService {
private readonly logger = new Logger(AppService.name);

@Once('ready')
public onReady(@Context() [client]: ContextOf<'ready'>) {
this.logger.log(`Bot logged in as ${client.user.username}`);
}

@On('warn')
public onWarn(@Context() [message]: ContextOf<'warn'>) {
this.logger.warn(message);
}
}
Warning

If you use global filters, guards or interceptors, they will be triggered once per event!
This means if you are replying to the message in guards, you can run into issues with duplicated responses or invalid interactions. Have a look at the NecordExecutionContext.getInfo() metadata to learn more about the current context.

Context

You might have noticed the @Context decorator in the last snippet: This is used to inject the event context within the method. As there are many type of events, its type must be inferred from the ContextOf<type: string> type.

You can access the context variables by using the @Context() decorator within your function, which will populate the variable with an array of arguments.

Text Commands

caution

A text command is dependent on the content of the message but unfortunately, Discord plans to remove message content for verified bots and apps, those with 100 or more servers. Hence, You cannot use text commands if your bot cannot access message content.

Read discord message here

Create a simple command handler for messages using @TextCommand.

src/app.service.ts
import { Injectable } from '@nestjs/common';
import { Context, TextCommand, TextCommandContext, Arguments } from 'necord';

@Injectable()
export class AppService {
@TextCommand({
name: 'ping',
description: 'Ping command!',
})
public onPing(@Context() [message]: TextCommandContext, @Arguments() args: string[]) {
return message.reply('pong!');
}
}

If all goes well, you should see something like this:

Text Command

Slash Commands

The best way to interact with your users is to use Slash commands! Slash commands allow you to create commands with precise arguments and choices, giving users the best experience.

To create a command with Necord, you can use the SlashCommand decorator.

app.service.ts
import { Injectable } from '@nestjs/common';
import { Context, SlashCommand, SlashCommandContext } from 'necord';

@Injectable()
export class AppService {
@SlashCommand({
name: 'ping',
description: 'Ping command!'
})
public async onPing(@Context() [interaction]: SlashCommandContext) {
return interaction.reply({ content: 'Pong!' });
}
}
tip

When the client logs in, it will automatically register all of the commands. Global commands are cached for up to an hour, therefore to avoid the global commands cache, you should use the development argument on the Necord module. This will restrict the command to a single guild, preventing it from getting caught by the cache.

Running the application

You can run the following command at your OS command prompt to start the application listening Discord API events:

$ npm run start