Configuring command cooldowns
Cooldowns are of vital importance for many bots to avoid excessive command usage, API ratelimits, and so on. Luckily,
Sapphire makes it easy to integrate them into your commands! At its simplest level, cooldowns can be used in specific
commands via the cooldownDelay
property in the command's options. This value is amount of
milliseconds that a user will have to wait after using a command to use it again. Here's a basic example:
- CommonJS
- ESM
- TypeScript
const { Command } = require('@sapphire/framework');
class PingCommand extends Command {
constructor(context) {
super(context, {
// ...
cooldownDelay: 10_000 // 10_000 milliseconds (10 seconds)
});
}
}
module.exports = {
PingCommand
};
import { Command } from '@sapphire/framework';
export class PingCommand extends Command {
constructor(context) {
super(context, {
// ...
cooldownDelay: 10_000 // 10_000 milliseconds (10 seconds)
});
}
}
import { Command } from '@sapphire/framework';
export class PingCommand extends Command {
public constructor(context: Command.LoaderContext) {
super(context, {
// ...
cooldownDelay: 10_000 // 10_000 milliseconds (10 seconds)
});
}
}
If you now try to run this command, and then run it again within 10_000 milliseconds (10 seconds), the command won't execute, and an error will be thrown. You can learn how to process that error here.
cooldownDelay
only accepts a value of milliseconds, which is not known to be the easiest to read or calculate. To
help, you can use @sapphire/time-utilities, which includes utilities for time transformers.
- CommonJS
- ESM
- TypeScript
const { Command } = require('@sapphire/framework');
const { Time } = require('@sapphire/time-utilities');
class PingCommand extends Command {
constructor(context) {
super(context, {
// ...
cooldownDelay: Time.Second * 10 // Much easier for humans to read
});
}
}
module.exports = {
PingCommand
};
import { Command } from '@sapphire/framework';
import { Time } from '@sapphire/time-utilities';
export class PingCommand extends Command {
constructor(context) {
super(context, {
// ...
cooldownDelay: Time.Second * 10 // Much easier for humans to read
});
}
}
import { Command } from '@sapphire/framework';
import { Time } from '@sapphire/time-utilities';
export class PingCommand extends Command {
public constructor(context: Command.LoaderContext) {
super(context, {
// ...
cooldownDelay: Time.Second * 10 // Much easier for humans to read
});
}
}
You can view the docs here.
User Exceptions
It's very common to not want cooldowns to apply to certain people, for example, the bot owner. This can be achieved by
adding cooldownFilteredUsers
to the options. This option should be an array of users ID that
the bot can ignore when calculating cooldowns.
- CommonJS
- ESM
- TypeScript
const { Command } = require('@sapphire/framework');
class PingCommand extends Command {
constructor(context) {
super(context, {
// ...
cooldownDelay: 10_000, // 10_000 milliseconds (10 seconds)
// 10_000 milliseconds (10 seconds)
cooldownFilteredUsers: ['YOUR_ID'] // Ignore the bot owner
});
}
}
module.exports = {
PingCommand
};
import { Command } from '@sapphire/framework';
export class PingCommand extends Command {
constructor(context) {
super(context, {
// ...
cooldownDelay: 10_000, // 10_000 milliseconds (10 seconds)
// 10_000 milliseconds (10 seconds)
cooldownFilteredUsers: ['YOUR_ID'] // Ignore the bot owner
});
}
}
import { Command } from '@sapphire/framework';
export class PingCommand extends Command {
public constructor(context: Command.LoaderContext) {
super(context, {
// ...
cooldownDelay: 10_000 // 10_000 milliseconds (10 seconds)
cooldownFilteredUsers: ['YOUR_ID'] // Ignore the bot owner
});
}
}
Advanced Usage
Accompanying cooldownDelay
, you also have access to the options cooldownLimit
and
cooldownScope
.
cooldownLimit
will define how many times a command can be used before a cooldown is put into affect. This value is set
to 1
by default. For example, a cooldownDelay
of 10_000
milliseconds and a cooldownLimit
of 2 will effectively
mean that you'd be able to use the command twice every 10 seconds.
Another useful option is cooldownScope
, which will define the scope of the cooldown. This is useful if you want to
have a cooldown that applies per guild, for example, instead of per user. Valid scopes can be found here.
Client-wide Cooldowns
Sometimes you'll find a use case where you want specific cooldown options to apply to all commands in your client. This
can be achieved by adding defaultCooldown
to your SapphireClient
options. You can use
any of the properties shown above with this option.
- CommonJS
- ESM
- TypeScript
const { SapphireClient, BucketScope } = require('@sapphire/framework');
const client = new SapphireClient({
intents: ['GUILDS', 'GUILD_MESSAGES'],
defaultCooldown: {
delay: 10_000, // 10_000 milliseconds
filteredCommands: ['ping'], // Ignore the `ping` command
filteredUsers: ['YOUR_ID'], // Ignore the bot owner
limit: 2, // Allow 2 uses before ratelimiting
scope: BucketScope.Channel // Scope cooldown to channel
}
});
void client.login('your-token-goes-here');
import { SapphireClient, BucketScope } from '@sapphire/framework';
const client = new SapphireClient({
intents: ['GUILDS', 'GUILD_MESSAGES'],
defaultCooldown: {
delay: 10_000, // 10_000 milliseconds
filteredCommands: ['ping'], // Ignore the `ping` command
filteredUsers: ['YOUR_ID'], // Ignore the bot owner
limit: 2, // Allow 2 uses before ratelimiting
scope: BucketScope.Channel // Scope cooldown to channel
}
});
void client.login('your-token-goes-here');
import { SapphireClient, BucketScope } from '@sapphire/framework';
const client = new SapphireClient({
intents: ['GUILDS', 'GUILD_MESSAGES'],
defaultCooldown: {
delay: 10_000, // 10_000 milliseconds
filteredCommands: ['ping'], // Ignore the `ping` command
filteredUsers: ['YOUR_ID'], // Ignore the bot owner
limit: 2, // Allow 2 uses before ratelimiting
scope: BucketScope.Channel // Scope cooldown to channel
}
});
void client.login('your-token-goes-here');
To learn how to send a message to the command executor when a precondition fails, see Reporting Precondition Failure.