You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The compiler plugin injects $ckitirl at build time. The runtime
wrapper uses a per-function key and the runtime default limiter.
The directive is applied only to async functions.
RateLimitEngine reset
RateLimitEngine.reset(key) removes both the main key and the violation:{key} entry.
HMR reset behavior
When a command file is hot-reloaded, the runtime plugin clears that command's
rate-limit keys using deleteByPattern (including violation: and :w: variants).
If the storage does not support pattern deletes, nothing is cleared.
Behavior details and edge cases
ratelimit() returns [UseRateLimitDirectivePlugin, RateLimitPlugin] in that order.
If required IDs are missing for a scope (for example no guild in DMs), that scope is skipped.
interval is clamped to at least 1ms when resolving limiter config.
RateLimitResult.limit is burst for token/leaky buckets and maxRequests for fixed/sliding windows.
Default rate-limit response uses an embed titled :hourglass_flowing_sand: You are on cooldown with a relative timestamp. Interactions reply ephemerally (or follow up if already replied/deferred). Non-repliable interactions are skipped. Messages reply only if the channel is sendable.
Queue behavior: queue size is pending + running; if maxSize is reached, the command is not queued and falls back to immediate rate-limit handling. Queued tasks stop after timeout and log a warning. After the initial delay, retries wait at least 250ms between checks. When queued, ctx.capture() and onRateLimited/onViolation hooks still run.
Bypass order is user/guild/role lists, then temporary exemptions, then bypass.check.
roleLimitStrategy: 'first' respects object insertion order. Role limits merge in this order: plugin roleLimits -> defaultLimiter.roleLimits -> named limiter roleLimits -> command overrides.
resetRateLimit triggers hooks.onReset for the key; resetAllRateLimits does not.
onStorageError is invoked with fallbackUsed = false from runtime plugin calls.
grantRateLimitExemption uses the runtime keyPrefix by default unless keyPrefix is provided.
RateLimitError defaults to message Rate limit exceeded.
If no storage is configured and default storage is disabled, the plugin logs once and stores an empty RateLimitStoreValue without limiting.
FallbackRateLimitStorage throws if either storage does not support an optional operation.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
@commandkit/ratelimit
Advanced rate limiting for CommandKit with multiple algorithms, queueing,
role limits, multi-window policies, and temporary exemptions.
Installation
Quick start
The runtime plugin auto-loads
ratelimit.ts/ratelimit.json startup.Enable rate limiting on a command:
ratelimit()optionsThe
ratelimit()factory returns the compiler and runtime plugins and accepts:compiler: Options for the"use ratelimit"directive transformer.Runtime options are configured via
configureRatelimit().Example:
How keys and scopes work
Scopes determine how keys are generated:
user->rl:user:{userId}:{commandName}guild->rl:guild:{guildId}:{commandName}channel->rl:channel:{channelId}:{commandName}global->rl:global:{commandName}user-guild->rl:user:{userId}:guild:{guildId}:{commandName}custom->keyResolver(ctx, command, source)If
keyPrefixis provided, it is prepended before therl:prefix:keyPrefix: 'prod:'->prod:rl:user:{userId}:{commandName}Multi-window limits add a suffix:
:w:{windowId}(for examplerl:user:123:ping:w:short)For
customscope you must providekeyResolver:If
keyResolverreturns a falsy value, the limiter is skipped for that scope.Exemption keys use:
rl:exempt:{scope}:{id}(plus optionalkeyPrefix).Plugin options (RateLimitPluginOptions)
defaultLimiter: Default limiter settings used when a command does not specify a limiter.limiters: Named limiter presets referenced by command metadata usinglimiter: 'name'.storage: Storage driver or{ driver }wrapper used for rate limit state.keyPrefix: Optional prefix prepended to all keys.keyResolver: Resolver used forcustomscope keys.bypass: Bypass rules for users, roles, guilds, or a custom check.hooks: Lifecycle hooks for allowed, limited, reset, violation, and storage error events.onRateLimited: Custom response handler that replaces the default reply.queue: Queue settings for retrying instead of rejecting.roleLimits: Role-specific limiter overrides.roleLimitStrategy:highest,lowest, orfirstto resolve matching role limits.initializeDefaultStorage: When true, initializes in-memory storage if no storage is set.initializeDefaultDriver: Alias forinitializeDefaultStorage.Limiter options (RateLimitLimiterConfig)
maxRequests: Requests allowed per interval (default 10).interval: Duration for the limit window (number in ms or string).scope: Single scope or list of scopes.algorithm:fixed-window,sliding-window,token-bucket,leaky-bucket.burst: Capacity for token/leaky bucket (defaults tomaxRequests).refillRate: Tokens per second for token bucket (defaults tomaxRequests / intervalSeconds).leakRate: Tokens per second for leaky bucket (defaults tomaxRequests / intervalSeconds).keyResolver: Custom key resolver forcustomscope.keyPrefix: Prefix override for this limiter.storage: Storage override for this limiter.violations: Escalation settings for repeated limits.queue: Queue override for this limiter.windows: Multi-window configuration.roleLimits: Role-specific overrides scoped to this limiter.roleLimitStrategy: Role limit resolution strategy scoped to this limiter.Command metadata options (RateLimitCommandConfig)
Command metadata extends limiter options and adds:
limiter: Name of a limiter defined inlimiters.Resolution order
Limiter resolution order (later overrides earlier):
DEFAULT_LIMITER).defaultLimiter.metadata.ratelimit.limiteris set).Algorithms
Fixed window
maxRequests,interval.consumeFixedWindoworincr, otherwise falls back toget/set.Sliding window log
maxRequests,interval.consumeSlidingWindowLogorzAdd,zRemRangeByScore,zCardand optionalzRangeByScore.consumeSlidingWindowLogfor strict enforcement.Token bucket
burst(capacity),refillRate(tokens/sec).get/set.refillRatemust be greater than 0.Leaky bucket
burst(capacity),leakRate(tokens/sec).get/set.leakRatemust be greater than 0.Storage drivers
MemoryRateLimitStorage
consumeFixedWindow,consumeSlidingWindowLog, sorted-set ops,prefix/pattern deletes, and key listing.
RedisRateLimitStorage
deleteByPattern,deleteByPrefix, andkeysByPrefixviaSCAN.@commandkit/ratelimit/redisalso re-exportsRedisOptionsfromioredis.FallbackRateLimitStorage
cooldownMs(default 30s).Disable the default memory storage:
Storage interface and requirements
storageaccepts either aRateLimitStorageinstance or{ driver }.Required methods:
get,set,delete.Optional methods used by features:
incrandconsumeFixedWindowfor fixed-window efficiency.zAdd,zRemRangeByScore,zCard,zRangeByScore,consumeSlidingWindowLogfor sliding window.ttl,expirefor expiry visibility.deleteByPrefix,deleteByPattern,keysByPrefixfor resets and exemption listing.Queue mode
Queue mode retries commands instead of rejecting immediately:
Queue options:
enabledmaxSizetimeoutdeferInteractionephemeralconcurrencyIf any queue config is provided and
enabledis unset, it defaults totrue.Queue defaults:
maxSize: 3timeout: 30sdeferInteraction: trueephemeral: trueconcurrency: 1deferInteractiononly applies to interactions (messages are ignored).maxSize,timeout, andconcurrencyare clamped to a minimum of 1.Queue resolution order is (later overrides earlier):
queuedefaultLimiter.queuenamed limiter queuecommand metadata queuerole limit queueRole limits
Role limits override the base limiter if the user has a matching role:
If no strategy is provided,
roleLimitStrategydefaults tohighest.Role scoring is based on
maxRequests / intervalMs(minimum across windows).Multi-window limits
Use
windowsto enforce multiple windows at the same time:If a window
idis omitted, it auto-generatesw1,w2, and so on.Violations and escalation
Escalate cooldowns after repeated rate limit violations:
If an escalation cooldown extends beyond the normal reset, the plugin
uses the longer cooldown.
Violation defaults and flags:
escalate: Defaults to true whenviolationsis set. Setfalseto disable escalation.maxViolations: Default 5.escalationMultiplier: Default 2.resetAfter: Default 1h.Hooks
Analytics events
The runtime plugin emits analytics events (if analytics is configured):
ratelimit_allowedratelimit_hitratelimit_violationEvents
Listen to runtime rate-limit events via CommandKit events:
Bypass rules
Custom rate-limited response
Override the default ephemeral cooldown reply:
Temporary exemptions
All exemption helpers accept an optional
keyPrefix.Listing notes:
listRateLimitExemptions({ scope, id })checks a single key directly.listRateLimitExemptions({ scope })scans by prefix if supported.limitcaps the number of results.expiresInMsisnullif the storage does not supportttl.Supported exemption scopes:
userguildrolechannelcategoryRuntime helpers and API
Runtime configuration
Storage helpers
Runtime access
Accessing results inside commands
Result shape
RateLimitStoreValueincludes:limited: Whether any limiter hit.remaining: Minimum remaining across all results.resetAt: Latest reset timestamp across all results.retryAfter: Max retry delay when limited.results: Array ofRateLimitResultentries.Each
RateLimitResultincludes:key,scope,algorithm,windowId?.limited,remaining,resetAt,retryAfter,limit.Reset helpers
Reset parameter notes:
resetRateLimitaccepts eitherkeyor (scope+commandName+ required IDs).resetAllRateLimitsacceptspattern,prefix,commandName, orscope+ IDs.keyPrefixcan be passed to both reset helpers.Directive:
use ratelimitUse the directive in async functions to rate-limit function execution:
The compiler plugin injects
$ckitirlat build time. The runtimewrapper uses a per-function key and the runtime default limiter.
The directive is applied only to async functions.
RateLimitEngine reset
RateLimitEngine.reset(key)removes both the main key and theviolation:{key}entry.HMR reset behavior
When a command file is hot-reloaded, the runtime plugin clears that command's
rate-limit keys using
deleteByPattern(includingviolation:and:w:variants).If the storage does not support pattern deletes, nothing is cleared.
Behavior details and edge cases
ratelimit()returns[UseRateLimitDirectivePlugin, RateLimitPlugin]in that order.intervalis clamped to at least 1ms when resolving limiter config.RateLimitResult.limitisburstfor token/leaky buckets andmaxRequestsfor fixed/sliding windows.:hourglass_flowing_sand: You are on cooldownwith a relative timestamp. Interactions reply ephemerally (or follow up if already replied/deferred). Non-repliable interactions are skipped. Messages reply only if the channel is sendable.maxSizeis reached, the command is not queued and falls back to immediate rate-limit handling. Queued tasks stop aftertimeoutand log a warning. After the initial delay, retries wait at least 250ms between checks. When queued,ctx.capture()andonRateLimited/onViolationhooks still run.bypass.check.roleLimitStrategy: 'first'respects object insertion order. Role limits merge in this order: pluginroleLimits->defaultLimiter.roleLimits-> named limiterroleLimits-> command overrides.resetRateLimittriggershooks.onResetfor the key;resetAllRateLimitsdoes not.onStorageErroris invoked withfallbackUsed = falsefrom runtime plugin calls.grantRateLimitExemptionuses the runtimekeyPrefixby default unlesskeyPrefixis provided.RateLimitErrordefaults to messageRate limit exceeded.RateLimitStoreValuewithout limiting.FallbackRateLimitStoragethrows if either storage does not support an optional operation.MemoryRateLimitStorage.deleteByPatternsupports*wildcards (simple glob).Constants
RATELIMIT_STORE_KEY:ratelimit(store key for aggregated results).DEFAULT_KEY_PREFIX:rl:(prefix used in generated keys).Type reference (exported)
RateLimitScopeandRATE_LIMIT_SCOPES: Scope values used in keys.RateLimitExemptionScopeandRATE_LIMIT_EXEMPTION_SCOPES: Exemption scopes.RateLimitAlgorithmTypeandRATE_LIMIT_ALGORITHMS: Algorithm identifiers.DurationLike: Number in ms or duration string.RateLimitQueueOptions: Queue settings for retries.RateLimitRoleLimitStrategy:highest,lowest, orfirst.RateLimitResult: Result for a single limiter/window.RateLimitAlgorithm: Interface for algorithm implementations.FixedWindowConsumeResultandSlidingWindowConsumeResult: Storage consume return types.RateLimitStorageandRateLimitStorageConfig: Storage interface and wrapper.ViolationOptions: Escalation controls.RateLimitWindowConfig: Per-window limiter config.RateLimitKeyResolver: Custom scope key resolver signature.RateLimitLimiterConfig: Base limiter configuration.RateLimitCommandConfig: Limiter config pluslimitername.RateLimitBypassOptions: Bypass lists and optionalcheck.RateLimitExemptionGrantParams,RateLimitExemptionRevokeParams,RateLimitExemptionListParams: Exemption helper params.RateLimitExemptionInfo: Exemption listing entry shape.RateLimitHookContextandRateLimitHooks: Hook payloads and callbacks.RateLimitResponseHandler:onRateLimitedhandler signature.RateLimitPluginOptions: Runtime plugin options.RateLimitStoreValue: Aggregated results stored inenv.store.ResolvedLimiterConfig: Resolved limiter config with defaults andintervalMs.RateLimitRuntimeContext: Active runtime state.Exports
ratelimitplugin factory (compiler + runtime).RateLimitPluginandUseRateLimitDirectivePlugin.RateLimitEngine, algorithm classes, andViolationTracker.MemoryRateLimitStorage,RedisRateLimitStorage,FallbackRateLimitStorage.configureRatelimit,setRateLimitStorage,getRateLimitStorage,setDriver,getDriver,getRateLimitRuntime,setRateLimitRuntime.getRateLimitInfo,resetRateLimit,resetAllRateLimits,grantRateLimitExemption,revokeRateLimitExemption,listRateLimitExemptions.RateLimitError.Defaults
maxRequests: 10interval: 60salgorithm:fixed-windowscope:userkeyPrefix: none (but keys always includerl:)initializeDefaultStorage: trueDuration units
String durations support
ms,s,m,h,dviams, plus:w,week,weeksmo,month,monthsSubpath exports
@commandkit/ratelimit/redis@commandkit/ratelimit/memory@commandkit/ratelimit/fallbackBeta Was this translation helpful? Give feedback.
All reactions