Quick start
Build your first slash command with TypeScript.
Let's make /ping. You'll need a Discord application and bot token from the Discord Developer Portal, plus Node.js and a package manager. The examples open on pnpm; you can switch to Yarn, Bun, or npm. Invite the bot to a test server with the bot and applications.commands scopes.
1. Start a project
Create a project folder, then choose your package manager:
mkdir my-bot && cd my-bot
pnpm init
pnpm add swagcommands discord.js
pnpm add -D typescript @types/nodeSWAGcommands v2 publishes a CommonJS package. This guide compiles TypeScript to CommonJS so the imports below work directly. Add scripts to package.json:
{
"scripts": {
"build": "tsc",
"start": "node dist/index.js"
}
}Create tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "CommonJS",
"moduleResolution": "Node",
"esModuleInterop": true,
"strict": true,
"rootDir": "src",
"outDir": "dist",
"skipLibCheck": true
},
"include": ["src"]
}2. Add a command
Create src/commands/ping.ts:
import { CommandType } from "swagcommands";
import type { CommandObject } from "swagcommands";
const ping = {
type: CommandType.SLASH,
description: "Check if the bot is awake",
callback: () => "Pong!",
} satisfies CommandObject;
export default ping;The filename supplies the command name. ping.ts becomes /ping. For slash commands, description is required.
3. Connect the client
Create src/index.ts:
import { once } from "node:events";
import { Client, Events, GatewayIntentBits } from "discord.js";
import SWAG from "swagcommands";
async function main() {
const token = process.env.DISCORD_TOKEN;
if (!token) throw new Error("Set DISCORD_TOKEN before starting the bot.");
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
const swag = await SWAG.create({
client,
commandsDir: "./dist/commands",
});
await client.login(token);
if (!client.isReady()) await once(client, Events.ClientReady);
// Sync the local slash command list with Discord.
await swag.deployCommands();
console.log(`Ready as ${client.user?.tag}`);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});Build and run:
pnpm build
DISCORD_TOKEN=your-token pnpm startTry /ping in your test server. Keep the token out of source control and logs. A local environment loader is fine too; it just needs to populate process.env.DISCORD_TOKEN before main() runs.
Deployment replaces the target command list
deployCommands() sends a complete manifest to Discord. Commands in that target scope that are missing from your local files are removed. Use a dedicated test application or be deliberate about which process owns the scope.
Next, learn how to add arguments, choose a deployment scope, or shut down features cleanly.