> For the complete documentation index, see [llms.txt](https://docs.nighty.one/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nighty.one/custom-features-tab/execution-limits.md).

# Execution Limits

## Why limits exist

Remember from [Events and Parameters Page](/custom-features-tab/understanding-events-and-parameters.md): events fire constantly. A busy server can produce hundreds of messages a minute, and **every single one** of them wakes up your feature.

Without a limit, a feature that replies to messages would reply to *all of them*, as fast as they arrive. That's how people get rate-limited by Discord or spam a channel by accident.

**Execution limits are your safety brake.** They cap how often a feature is allowed to actually do something.

Nighty gives you two kinds:

| Kind                 | Question it answers                                                                     |
| -------------------- | --------------------------------------------------------------------------------------- |
| **Global limit**     | How often may this feature run *in total*?                                              |
| **Parameter limits** | How often may it run *for each individual parameter (person / server / channel / ...)*? |

You can use one, the other, or both together.

## The global limit

The global limit is the simple one:

> **This feature may run X times per Y seconds.**

It counts **every** run of the feature, no matter who triggered it or where.

**The default is 1 time per 1 second**, and you should usually leave it there or make it stricter. It costs you almost nothing in normal use, and it's the thing standing between you and a runaway feature that fires two hundred times in a minute.

{% hint style="warning" %}
**We strongly recommend keeping the global limit at 1 per 1 second or higher.** Only remove it if you have a specific reason and you're sure the feature is safe to run without a brake.
{% endhint %}

A few examples of what different settings mean:

| Setting                   | Meaning                                                         |
| ------------------------- | --------------------------------------------------------------- |
| 1 time per 1 second       | The default. At most one run each second.                       |
| 1 time per 60 seconds     | At most one run per minute, no matter how busy things get.      |
| 5 times per 60 seconds    | Up to 5 runs a minute. A 6th trigger in that minute is ignored. |
| 10 times per 3600 seconds | Up to 10 runs per hour.                                         |

**How the window works:** it's a rolling window, not a fixed clock. "5 times per 60 seconds" means *"in the last 60 seconds, have I already run 5 times?"* - it does not reset on the minute. As old runs age past 60 seconds they drop off and free up space again.

## Limits based on parameters

This is the powerful one, and it's easier than it sounds.

A global limit treats everyone the same. If your feature just ran, it's on cooldown **for everybody** - the next person to trigger it gets ignored, even though it was somebody else who used up the run.

Often that's not what you want. What you usually want is:

> *"Once per person. Anna using it shouldn't stop Ben from using it."*

That's exactly what a parameter limit does.

### The idea

You pick a **parameter from your event** - `user`, `guild`, `channel`, `member`, `role`, and so on - and set a limit on it.

Nighty then keeps **a separate counter for every individual one of those things.**

Set a limit on `user`, and every single person gets their own private counter. Anna has hers, Ben has his. They don't affect each other at all.

> 🎟️ **Think of it like a ticket booth.** A global limit is one ticket for the whole room - once it's taken, nobody else gets in until it's back. A parameter limit hands **everyone their own ticket**. Using yours doesn't touch mine.

### A worked example

Say you build a feature that replies with a welcome message when someone posts. You set:

> **Parameter limit on `user`: 1 time per 60 seconds**

<figure><img src="/files/soc3h9bJ40NyE7M2Cxff" alt=""><figcaption></figcaption></figure>

Here's what happens:

| Time     | What happens                   | Result                                   |
| -------- | ------------------------------ | ---------------------------------------- |
| 12:00:00 | **Anna** sends a message       | ✅ Feature runs - Anna's 60 seconds start |
| 12:00:05 | **Anna** sends another message | ❌ Blocked - Anna is on cooldown          |
| 12:00:06 | **Ben** sends a message        | ✅ Feature runs - Ben has his own counter |
| 12:00:20 | **Ben** sends another message  | ❌ Blocked - Ben is on cooldown           |
| 12:01:01 | **Anna** sends a message       | ✅ Runs - Anna's 60 seconds are up        |

One feature, one limit, but **each person is tracked separately**.

### Two things to know

**Your own account is never limited.** The `me` parameter can't be used for limits. There'd be no point - there's only one of you, so a limit on `me` would just be the global limit again.

**If the parameter isn't in the event, the limit is skipped.** Remember from [Events and Parameters Page](/custom-features-tab/understanding-events-and-parameters.md) that a DM has no `guild` and no `member`. If you put a limit on `guild` and the feature is triggered by a DM, there's no server to count against, so that particular limit simply doesn't apply to that run. Your other limits (including the global one) still do.

{% hint style="info" %}
That's another good reason to always keep the global limit on - it's the one that's guaranteed to apply every time.
{% endhint %}

## "X times per Y seconds" vs "X times total"

Every limit has two settings: **how many times**, and **per how many seconds**.

But you can also switch the time part **off**. That changes the meaning completely:

| Setup                      | Meaning                                                                |
| -------------------------- | ---------------------------------------------------------------------- |
| 3 times **per 60 seconds** | 3 runs allowed in any 60-second window. Space frees up as time passes. |
| 3 times, **time off**      | 3 runs allowed **in total**. Once used, that's it - it never frees up. |

The second one is a **hard budget** rather than a cooldown. It's useful for one-shot things: *"welcome each new member exactly once"* (put it on `member` with the time off), or a feature you want to fire a fixed number of times and then stop.

{% hint style="info" %}
A total budget isn't permanent forever - it resets when the limit is reset.
{% endhint %}

## When does a run actually get counted?

This one surprises people, and it's good news.

**A trigger only counts against your limits if the feature actually did something.**

Walk through what happens when an event arrives:

{% stepper %}
{% step %}

### The event fires

The event fires and the feature wakes up.
{% endstep %}

{% step %}

### Filters and conditions are checked

Filters and conditions are checked.
{% endstep %}

{% step %}

### Nothing passes

**If nothing passes and there are no actions to run** → nothing is counted. Your limit is untouched.
{% endstep %}

{% step %}

### Actions run

**If actions do run** → *that's* when the run is counted and your limits are consumed.
{% endstep %}
{% endstepper %}

So a feature that reacts only to messages containing "hello" does **not** burn its cooldown on the hundreds of other messages it looked at and ignored. It only spends a run when it genuinely replies.

This means you can set a tight limit like "1 per 60 seconds" without worrying that background chatter will silently eat it.

## When limits reset

Your limit counters are cleared in these situations:

| What you do                  | Effect                            |
| ---------------------------- | --------------------------------- |
| **Edit the feature**         | All of its limits reset to empty  |
| **Turn it off and on again** | All of its limits reset           |
| **Rename it**                | All of its limits reset           |
| **Restart Nighty**           | All limits for all features reset |

Counters are kept in memory while Nighty is running, not saved to disk. So if you set a "5 times total" budget and restart Nighty, you get a fresh 5.

{% hint style="info" %}
This is handy while you're building something. If you're testing and keep hitting your own cooldown, just toggle the feature off and back on to clear it.
{% endhint %}
