Loading documentation...
Introduction
Guardrail is an open-source security toolkit that provides rate limiting, bot detection, and attack protection for Node.js applications. It runs entirely on your infrastructure with no external dependencies or usage-based pricing.
Key Features
- Zero-Config — Get started with built-in presets and auto-discovery
- Rate Limiting — Token bucket and sliding window algorithms
- Bot Detection — Identify and block automated traffic
- IP Intelligence — Geolocation with VPN/proxy detection
- Email Validation — Block disposable and invalid emails
- Attack Protection — Shield against SQL injection, XSS, and more
- Framework Support — Next.js, Express, Nest.js, Fastify, and Koa
Installation
Install Guardrail using npm or your preferred package manager:
npm install @guardrail-dev/core
For Redis storage support in distributed deployments:
npm install @guardrail-dev/core ioredis
Quick Start
Guardrail is designed to be developer-first. You can start protecting your app with zero configuration:
import { guardrail } from "@guardrail-dev/core";
// 1. Zero-config (uses API preset + auto-detects Redis)
const gr = guardrail();
export async function POST(req: Request) {
const decision = await gr.protect(req);
if (decision.isDenied()) return new Response("Forbidden", { status: 403 });
return new Response("OK");
}
Next.js Integration
Seamlessly protect your Next.js middleware and API routes.
Middleware
import { guardrailNext } from "@guardrail-dev/core/next";
// One-liner middleware protection
export const middleware = guardrailNext.api().middleware();
API Routes (App or Pages Router)
import { protect } from "@guardrail-dev/core/next";
export default protect(async (req, res) => {
// Secured automatically
res.json({ success: true });
});
Express.js Integration
Simple middleware factories with semantic presets.
import express from "express";
import { guardrailExpress } from "@guardrail-dev/core/express";
const app = express();
// Global protection
app.use(guardrailExpress.api());
// Route-specific with custom rules
app.post("/login", guardrailExpress.auth({ debug: true }));
Fastify & Koa
Consistent protection for every major framework.
Fastify
import { guardrailFastify } from "@guardrail-dev/core/fastify";
fastify.addHook("preHandler", guardrailFastify.api());
Koa
import { guardrailKoa } from "@guardrail-dev/core/koa";
app.use(guardrailKoa.web());
Nest.js Integration
Register Guardrail as a module and use the ultimate decorator-driven security experience.
Module Registration
import { Module } from "@nestjs/common";
import { GuardrailModule } from "@guardrail-dev/core/nestjs";
@Module({
imports: [
GuardrailModule.forRoot({
autoProtect: true, // Automatically protect every route
useGuard: true,
}),
],
})
export class AppModule {}
Ultimate Decorators
Add protection to specific controllers or routes with single-line decorators:
import { Controller, Post } from "@nestjs/common";
import { Limit, Shield, BlockVPN, Result } from "@guardrail-dev/core/nestjs";
@Controller("payments")
@Shield() // Protect all routes in this controller
export class PaymentsController {
@Post()
@Limit({ max: 5, interval: "1m" }) // Override rate limit
@BlockVPN() // Shortcut for VPN blocking
async process(@Result() decision: Decision) {
return { id: decision.id };
}
}
Rules Overview
Guardrail uses a rule-based system to evaluate requests. Rules are evaluated in order, and each rule returns an ALLOW or DENY decision.
| Rule | Description | Import |
|---|---|---|
shield |
Attack protection (SQL injection, XSS, etc.) | shield() |
bot |
Bot detection and blocking | bot({ allow: [] }) |
window |
Rate limiting with sliding window | window({ interval, max }) |
bucket |
Rate limiting with token bucket | bucket({ capacity, refillRate }) |
email |
Email validation and blocking | email({ block: [...] }) |
filter |
Expression-based filtering | filter({ deny: [...] }) |
Rate Limiting
Sliding Window
Limit the number of requests within a time window:
import { window } from "@guardrail-dev/core";
window({
interval: "10m", // Time window
max: 100, // Maximum requests
});
Token Bucket
For more complex rate limiting, especially useful for AI quota control:
import { bucket } from "@guardrail-dev/core";
bucket({
by: ["userId"], // Rate limit per user
refillRate: 2000, // Tokens added per interval
interval: "1h", // Refill interval
capacity: 5000, // Maximum token capacity
});
// Usage with token consumption
const decision = await gr.protect(req, {
userId: "user123",
requested: estimatedTokens,
});
if (decision.reason.isQuota()) {
const remaining = decision.reason.getRemaining();
console.log(`Tokens remaining: ${remaining}`);
}
Bot Detection
Detect and block automated traffic while allowing specific bots:
import { bot } from "@guardrail-dev/core";
// Block all bots
bot({ allow: [] });
// Allow specific bots
bot({
allow: ["Googlebot", "Bingbot", "Slackbot"],
});
Shield (Attack Protection)
Protect against common web attacks:
import { shield } from "@guardrail-dev/core";
// Default protection
shield();
// Dry run mode (log but don't block)
shield({ mode: "DRY_RUN" });
Shield protects against:
- SQL injection attacks
- Cross-site scripting (XSS)
- Command injection
- Path traversal
Email Validation
Block problematic email addresses:
import { email } from "@guardrail-dev/core";
email({
block: [
"DISPOSABLE", // Temporary email services
"INVALID", // Invalid format
"NO_MX_RECORDS", // No mail server
"FREE", // Free email providers
],
});
// Usage
const decision = await gr.protect(req, {
email: "user@example.com",
});
Filter Rules
Create custom filters using expressions:
import { filter } from "@guardrail-dev/core";
// Block non-US traffic
filter({
deny: ['ip.src.country ne "US"'],
});
// Allow only specific IPs
filter({
allow: ["ip.src in { 1.2.3.4 5.6.7.8 }"],
});
// Complex expressions
filter({
deny: [
"ip.src.vpn == true",
'ip.src.country in ["XX", "YY"]',
'ip.src.country ne "US" and ip.src.proxy == true',
],
});
Supported Operators
| Operator | Description | Example |
|---|---|---|
==, != |
Equality comparison | ip.src.vpn == true |
>, <, >=, <=
|
Numeric comparison | request.count > 100 |
in |
Membership check | ip.src.country in ["US", "CA"] |
and, or, not |
Logical operators | vpn == true and proxy == true |
matches |
Regex matching | path matches "^/api/" |
IP Intelligence
Access detailed IP information for every request:
const decision = await gr.protect(req);
// Geolocation
if (decision.ip.hasCountry()) {
console.log(decision.ip.country); // "US"
console.log(decision.ip.countryName); // "United States"
}
if (decision.ip.hasRegion()) {
console.log(decision.ip.region); // "California"
}
if (decision.ip.hasCity()) {
console.log(decision.ip.city); // "San Francisco"
}
// Network detection
if (decision.ip.isVpn()) {
console.log("VPN detected");
}
if (decision.ip.isProxy()) {
console.log("Proxy detected");
}
if (decision.ip.isHosting()) {
console.log("Hosting provider detected");
}
Premium IP Providers
For production environments, we recommend using dedicated IP intelligence providers for higher accuracy and rate limits.
MaxMind GeoIP2
import { guardrail, MaxMindProvider } from "@guardrail-dev/core";
const gr = guardrail({
ipService: new MaxMindProvider({
accountId: process.env.MAXMIND_ACCOUNT_ID,
licenseKey: process.env.MAXMIND_LICENSE_KEY,
serviceType: "insights", // "country", "city", or "insights"
}),
rules: [/* ... */],
});
IPinfo.io
import { guardrail, IPinfoProvider } from "@guardrail-dev/core";
const gr = guardrail({
ipService: new IPinfoProvider({
token: process.env.IPINFO_TOKEN,
}),
rules: [/* ... */],
});
Fallback Strategy
Chain multiple providers to ensure high availability:
import { guardrail, FallbackIPProvider, MaxMindProvider, IPinfoProvider } from "@guardrail-dev/core";
const gr = guardrail({
ipService: new FallbackIPProvider([
new MaxMindProvider({ /* ... */ }),
new IPinfoProvider({ /* ... */ }),
]),
rules: [/* ... */],
});
Standalone VPN/Proxy Detection
Use the advanced VPN detection logic independently of the main guardrail pipeline:
import { VPNProxyDetection } from "@guardrail-dev/core";
const vpnDetector = new VPNProxyDetection({
enableHeuristicDetection: true,
confidenceThreshold: 50,
customVPNProviders: ["my-internal-vpn"],
});
// Check an IP
const result = await vpnDetector.check("1.2.3.4");
if (result.isVpn) {
console.log("VPN detected via:", result.method);
}
// Get detection statistics
console.log(vpnDetector.getProviderCounts());
Storage Backends
Memory Storage
Default storage for single-instance deployments:
import { guardrail, MemoryStorage } from "@guardrail-dev/core";
const gr = guardrail({
storage: new MemoryStorage(10000), // Max cache size
rules: [/* ... */],
});
Redis Storage
For distributed deployments with multiple instances:
import { guardrail, RedisStorage } from "@guardrail-dev/core";
const gr = guardrail({
storage: new RedisStorage(process.env.REDIS_URL),
rules: [/* ... */],
});
Configuration
const gr = guardrail({
rules: [/* ... */],
// Error handling mode
errorHandling: "FAIL_CLOSED", // or "FAIL_OPEN" (default)
// Evaluation strategy
evaluationStrategy: "PARALLEL", // or "SEQUENTIAL", "SHORT_CIRCUIT"
// Debug mode
debug: true,
// Whitelist
whitelist: {
ips: ["1.2.3.4"],
userIds: ["admin"],
countries: ["US", "CA"],
},
// Blacklist
blacklist: {
ips: ["5.6.7.8"],
countries: ["XX"],
},
});
Error Handling Modes
- FAIL_OPEN (default) — On errors, allow requests through
- FAIL_CLOSED — On errors, deny requests (more secure)
Evaluation Strategies
- SEQUENTIAL (default) — Evaluate rules one by one
- PARALLEL — Evaluate all rules simultaneously
- SHORT_CIRCUIT — Stop on first DENY decision
Metrics & Events
Metrics Collection
const gr = guardrail({
rules: [/* ... */],
debug: true,
});
// Get metrics
const metrics = gr.getMetrics();
console.log(metrics.getMetrics());
// Available metrics:
// - guardrail.requests.total
// - guardrail.decisions.allowed
// - guardrail.decisions.denied
// - guardrail.request.duration
// - guardrail.rule.{ruleType}.duration
Event System
gr.on("decision.denied", (event) => {
console.log("Denied:", event.decision);
});
gr.on("rule.evaluate", (event) => {
console.log("Evaluating:", event.ruleType);
});
// Available events:
// - rule.evaluate
// - rule.allow
// - rule.deny
// - decision.allowed
// - decision.denied
// - storage.error
// - ip-lookup.error
API Reference
guardrail(config)
Creates a new Guardrail instance.
| Option | Type | Description |
|---|---|---|
rules |
Array | Array of rule configurations (required) |
storage |
Storage | Storage adapter (default: MemoryStorage) |
ipService |
IPService | IP geolocation service |
errorHandling |
String | "FAIL_OPEN" or "FAIL_CLOSED" |
evaluationStrategy |
String | "SEQUENTIAL", "PARALLEL", or "SHORT_CIRCUIT" |
debug |
Boolean | Enable debug mode and metrics |
whitelist |
Object | Whitelist configuration |
blacklist |
Object | Blacklist configuration |
protect(request, options?)
Evaluates a request against all configured rules and returns a decision.
| Option | Type | Description |
|---|---|---|
userId |
String | User identifier for rate limiting |
email |
String | Email address for validation |
requested |
Number | Number of tokens/requests requested |
Examples
Payment Form Protection
const gr = guardrail({
rules: [
shield(),
bot({ allow: [] }),
email({
block: ["DISPOSABLE", "INVALID", "NO_MX_RECORDS"],
}),
window({ interval: "10m", max: 5 }),
],
whitelist: {
ips: ["1.2.3.4"], // Admin IP
},
});
export async function POST(req: Request) {
const { email } = await req.json();
const decision = await gr.protect(req, { email });
if (decision.isDenied()) {
if (decision.reason.isBot()) {
return new Response("Bot detected", { status: 403 });
}
if (decision.reason.isEmail()) {
return new Response("Invalid email", { status: 400 });
}
if (decision.reason.isRateLimit()) {
return new Response("Rate limit exceeded", { status: 429 });
}
}
// Process payment
return new Response("Payment processed");
}
AI Quota Control
const gr = guardrail({
rules: [
bucket({
by: ["userId"],
refillRate: 2000,
interval: "1h",
capacity: 5000,
}),
],
evaluationStrategy: "SHORT_CIRCUIT",
});
export async function POST(req: Request) {
const { userId, prompt } = await req.json();
const estimatedTokens = estimateTokens(prompt);
const decision = await gr.protect(req, {
userId,
requested: estimatedTokens,
});
if (decision.reason.isQuota()) {
const remaining = decision.reason.getRemaining();
return Response.json(
{ error: "Quota exceeded", remaining },
{ status: 429 }
);
}
// Process AI request
return Response.json({ success: true });
}
Testing
Guardrail includes testing utilities for unit and integration tests:
import { createTestGuardrail } from "@guardrail-dev/core/testing";
import { shield, window } from "@guardrail-dev/core";
const { guardrail, storage, ipService } = createTestGuardrail({
rules: [
shield(),
window({ interval: "1m", max: 100 }),
],
});
// Mock IP data
ipService.setIP("1.2.3.4", {
country: "US",
countryName: "United States",
city: "San Francisco",
});
// Test your code
const decision = await guardrail.protect(req);
expect(decision.isAllowed()).toBe(true);
Known Limitations
IP Geolocation
- Default provider uses free APIs with rate limits (ipapi.co: 1000/day, ip-api.com: 45/min)
-
Recommendation: Use
MaxMindProvider,IPinfoProvider, orIPQualityScoreProviderfor production
VPN/Proxy Detection
- Detection is based on ASN name matching against a comprehensive (100+) but not exhaustive list
-
Recommendation: Use
IPQualityScoreProviderfor advanced fraud detection
Bot Detection
- Basic detection uses User-Agent matching only
-
Recommendation: Use
bot()with configuration for header analysis and behavioral signals - Client-side fingerprinting requires a separate implementation
Rate Limiting
MemoryStoragedoes not sync across Node.js cluster workers-
Recommendation: Use
AtomicRedisStoragefor distributed deployments
Attack Protection
- Guardrail is not a replacement for enterprise WAF solutions (Cloudflare, AWS WAF)