MySQL Store
The MySQL store enables distributed rate limiting using your existing MySQL database. Ideal for teams running LAMP stacks, WordPress infrastructure, or any MySQL-backed application who want to add rate limiting without introducing Redis.
Installation
The MySQL store requires mysql2 as a peer dependency:
npm install mysql2
# or: pnpm add mysql2
# or: yarn add mysql2 bun add mysql2 Usage
import { hitlimit } from '@joint-ops/hitlimit'
import { mysqlStore } from '@joint-ops/hitlimit/stores/mysql'
import mysql from 'mysql2/promise'
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'secret',
database: 'myapp'
})
app.use(hitlimit({
limit: 100,
window: '1m',
store: mysqlStore({ pool })
})) import { hitlimit } from '@joint-ops/hitlimit-bun'
import { mysqlStore } from '@joint-ops/hitlimit-bun/stores/mysql'
import mysql from 'mysql2/promise'
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'secret',
database: 'myapp'
})
const limiter = hitlimit({
limit: 100,
window: '1m',
store: mysqlStore({ pool })
}) Options
| Option | Type | Default | Description |
|---|---|---|---|
pool | Pool | - | A mysql2/promise Pool instance (required) |
tablePrefix | string | 'hitlimit' | Prefix for rate limit table names |
cleanupInterval | number | 60000 | Interval (ms) to clean expired entries |
skipTableCreation | boolean | false | Skip automatic table creation on startup |
Schema
The store automatically creates the following InnoDB tables (prefix defaults to hitlimit):
CREATE TABLE IF NOT EXISTS hitlimit_hits (
`key` VARCHAR(255) NOT NULL PRIMARY KEY,
count INT NOT NULL DEFAULT 1,
reset_at BIGINT NOT NULL
) ENGINE=InnoDB
CREATE TABLE IF NOT EXISTS hitlimit_bans (
`key` VARCHAR(255) NOT NULL PRIMARY KEY,
expires_at BIGINT NOT NULL
) ENGINE=InnoDB
CREATE TABLE IF NOT EXISTS hitlimit_violations (
`key` VARCHAR(255) NOT NULL PRIMARY KEY,
count INT NOT NULL DEFAULT 1,
reset_at BIGINT NOT NULL
) ENGINE=InnoDB MySQL vs PostgreSQL
| Aspect | MySQL | PostgreSQL |
|---|---|---|
| Atomicity | INSERT ON DUPLICATE KEY UPDATE + LAST_INSERT_ID() | ON CONFLICT DO UPDATE + named prepared statements |
| Cleanup | Timer-based (DELETE WHERE expired) | Timer-based (DELETE WHERE expired) |
| Driver | mysql2 | pg |
| Extra infra | None (use existing DB) | None (use existing DB) |
| Compatibility | MySQL 5.7+, MariaDB, PlanetScale | PostgreSQL 12+ |
Characteristics
- Persistence: Full MySQL/InnoDB durability (redo log, replication)
- Scalability: Shared across all server instances
- Atomic:
INSERT ON DUPLICATE KEY UPDATEwithLAST_INSERT_ID()ensures race-condition-free increments - Cleanup: Periodic timer deletes expired rows (configurable interval)
- Dependencies: Requires
mysql2driver (>=3.0.0)
When to Use
- Teams already running MySQL in production
- LAMP stack and WordPress-ecosystem applications
- PlanetScale, AWS RDS, or MariaDB users
- When you want distributed rate limiting without adding Redis or Postgres
- MySQL-first architectures with existing connection pools