An interactive guide to the three algorithms in elysia-rate-limiter

View source
Interactive guide

Watch rate limiters decide, one request at a time.

Send requests, bend time, and follow each one through a fixed window, a sliding window and a token bucket. Every step shows the real numbers from the code.

Open the playground
Playground

Same traffic, three algorithms

Every request goes to all three algorithms at the same moment. Turn up the traffic, try a scenario, or click any dot to see why that request was allowed or rejected.

time0s

Try a scenario

Each one schedules requests on the shared clock

Following the latest request. Click any dot to pin it and compare the three verdicts.
01fixed-window

Fixed window

One counter per clock-aligned window.

window 0s → 6sresets in 6s

0 of 5 slots used in this window. They all empty at the boundary.

Allowed
0
Rejected
0
Room
5/5
Next
now
−12swindow boundaries are dashednow

Step by step

Send a request to watch this algorithm decide.

02sliding-window

Sliding window

Weighs the previous window into a rolling estimate.

limit 5rolling windowprevious · 0current · 0

0×100%+0=0of 5

Allowed
0
Rejected
0
Room
5/5
Next
now
−12swindow boundaries are dashednow

Step by step

Send a request to watch this algorithm decide.

03token-bucket

Token bucket

Tokens drip in steadily, and each request spends one.

5of 5 tokens

+1 token every 1.2s · the bucket is full

Allowed
0
Rejected
0
Room
5/5
Next
now
−12swindow boundaries are dashednow

Step by step

Send a request to watch this algorithm decide.

How it works

Three algorithms, a few numbers each

Each algorithm keeps a few numbers per client, so memory per client never grows. They differ in how they turn those numbers into a yes or a no.

01

Fixed window

algorithm: 'fixed-window'

Time is cut into clock-aligned windows. Each window has a counter that resets when the next window begins.

  1. Round the current time down to the start of its window.
  2. If the stored counter belongs to an older window, start again at 0.
  3. Allow the request if count + cost stays within the limit.
Stores per client
{ windowStart, count }
Good for
Simple quotas that are easy to explain, like 5 login attempts per 15 minutes.
Watch out
A client can send a full limit just before a reset and another just after it: 2× the limit in a moment.
02

Sliding window

algorithm: 'sliding-window'

Keeps the current and previous window counts, then weighs the previous one by how much of it still overlaps a rolling window ending now.

  1. Roll the counters forward if a new window has started.
  2. weight = the share of the previous window still inside the rolling window.
  3. Allow the request if previous × weight + current + cost stays within the limit.
Stores per client
{ windowStart, previous, current }
Good for
Most APIs and pages. It smooths out the boundary spike at almost no extra cost. This is the default.
Watch out
It is an estimate: it assumes the previous window’s requests were spread evenly.
03

Token bucket

algorithm: 'token-bucket'

A bucket holds up to limit tokens and refills evenly over the window. Every request takes tokens out.

  1. Add tokens for the time since the last update: elapsed × limit ÷ window.
  2. Never fill past the bucket size.
  3. Allow the request if there are at least cost tokens, then take them.
Stores per client
{ tokens, updatedAt }
Good for
APIs that should absorb short bursts but hold a steady average rate.
Watch out
A full bucket lets a whole limit through at once, so size it for the burst you can handle.
Usage

Pick the one you just watched

Every algorithm in the playground is one option away. The plugin sends standard RateLimit-* headers and aRetry-After on every 429.

Quick start
import { Elysia } from 'elysia'
import { rateLimit } from 'elysia-rate-limiter'

const app = new Elysia()
  .use(rateLimit({ limit: 100, window: '1m', algorithm: 'sliding-window' }))
  .get('/', () => 'Hello')
  .listen(3000)
Allow bursts on an API group
new Elysia()
  .group('/api', (api) =>
    api
      .use(
        rateLimit({
          limit: 1_000,
          window: '1m',
          algorithm: 'token-bucket',
        }),
      )
      .get('/search', search),
  )
FAQ

Questions developers ask

Which algorithm should I start with?

The sliding window, which is the default. It behaves like a fixed window without the spike at the boundary, and still stores only three numbers per client. Pick the token bucket when short bursts are fine as long as the average stays steady, or the fixed window when a quota has to line up with the clock.

Why can a fixed window let through twice the limit?

The counter resets at every boundary. A client that sends a full limit just before the reset and another full limit just after gets twice the limit in a moment. Run the “Window boundary trick” scenario in the playground and watch it happen.

Is the sliding window count exact?

No, it is an estimate. It assumes the previous window’s requests were spread evenly and counts only the share that still overlaps the rolling window. In practice it stays close to an exact log of timestamps while using constant memory.

What do RateLimit-Remaining and Retry-After mean?

RateLimit-Remaining is how many more requests fit right now. RateLimit-Reset and Retry-After are whole seconds, rounded up, until the limit resets or until a rejected client should try again. Each card shows the exact headers the plugin would send.

Does this page talk to a server?

No. The real algorithm classes run in your browser on a simulated clock, so you can pause, speed up and replay traffic. The plugin runs the same evaluate() code against a memory or Redis store.