Security is the area where it's most cost-efficient to make it effective at the entrance, "before writing app code." Vercel has three layers at the platform level — DDoS mitigation, WAF, BotID — letting you trim the attack surface with minimal code changes. This article summarizes how to defend the entrance with real code, faithful to the official specs of Vercel Firewall, Vercel WAF, and BotID.
For the full picture, see the Vercel production-operations guide.
An important premise: this article is about platform-layer (entrance) security. App-layer authorization, RLS, and injection defense (IDOR/SQLi/XSS/SSRF) can't be protected by a WAF. They're separate layers, designed as both wheels. For the app layer, see Next.js × Supabase application-layer security.
The role division of the three layers
| Layer | What it protects | Plan |
|---|---|---|
| DDoS mitigation | Exhaustion attacks via mass requests | All plans (automatic, free) |
| WAF | Blocking/challenging/rate-limiting/IP-blocking malicious requests | Hobby/Pro/Enterprise (scale differs) |
| BotID | Advanced bots posing as humans (scraping, credential stuffing) | Basic free on all plans / Deep Analysis Pro·Ent |
On the foundation of "DDoS mitigation that works broadly and automatically," layer "WAF that controls narrowly with rules" and "BotID that distinguishes human/bot" — this is the entrance's defense in depth.
DDoS mitigation: automatic on all plans
Vercel's DDoS mitigation works automatically on all plans. With no configuration, it absorbs mass L3/L4/L7 requests. When an attack is severe, use the Attack Challenge Mode described below alongside. This is a state where "the foundation is protected even without doing anything," and you add intentional control here with WAF and BotID.
Vercel WAF: entrance rules that propagate in 300ms
Vercel WAF is a mechanism that monitors and controls traffic to the site by logging, blocking, and challenging. Its biggest feature is operability — setting changes propagate globally in 300ms, and on a problem you can instantly roll back from the audit log (WAF docs).
Three control means
| Means | Content |
|---|---|
| IP block | Block specific IPs/CIDRs |
| Custom rules | Declarative condition → action rules |
| Managed rule sets | Off-the-shelf rule groups like OWASP (Enterprise) |
Limits by plan
| Feature | Hobby | Pro | Enterprise |
|---|---|---|---|
| Project IP blocks | Up to 3 | Up to 100 | Up to 1000 |
| Custom rules | Up to 3 | Up to 40 | Up to 1000 |
| Managed rule sets | — | — | Yes |
How to think about custom rules
A custom rule ties an "action" to a "condition (path, IP, region, request header, User-Agent, JA4, etc.)." The actions are —
- Allow: let through (allowlist)
- Deny: block
- Challenge: challenge (verify human)
- Log: record only (observe first, then tighten)
- Rate Limit: limit by count per period
The iron rule in practice is "observe with Log first → confirm the impact → escalate to Deny/Challenge." Avoid the incident of jumping straight to Deny and catching legitimate users. With 300ms propagation and instant rollback, this "observe then tighten" operation runs safely.
Rate limiting: stop abuse structurally
For high-value routes prone to abuse like login and search, use WAF rate limiting to Challenge/Deny when "N times/minute from the same IP" is exceeded.
Relationship with Fluid Compute: in-app rate limiting (a memory counter) doesn't work correctly on serverless (since instances are shared/distributed). Use WAF rate limiting that works at the entrance, or distributed rate limiting with Upstash (Redis). WAF rate limiting works before the function is called, so it also prevents Active CPU billing.
Configuration and rollback (the operations flow)
ダッシュボード → プロジェクト → Firewall
① Custom Rule を Log で追加 → トラフィックを観測
② 影響を確認したら Deny / Challenge / Rate Limit へ昇格(300msで反映)
③ 誤遮断が出たら View Audit Log → 過去構成へ Restore(即時ロールバック)
You can also stage rules in the CLI and apply them in bulk (vercel firewall). Suited to teams that want to review and apply rules in an Infrastructure-as-Code manner.
Attack Challenge Mode: the emergency valve during an attack
When an attack is severe, turning Attack Challenge Mode ON imposes a temporary challenge on all visitors and greatly reduces automated traffic. Legitimate users get a minor confirmation, and you turn it OFF once the attack subsides. A two-stage setup: "precise rules in peacetime, one mode toggle in an emergency."
BotID: invisible CAPTCHA
A "pick the images" UI like reCAPTCHA hurts UX while getting broken by advanced bots. BotID is an invisible CAPTCHA based on Kasada — without user interaction, it detects bots "posing as humans" like Playwright/Puppeteer (BotID docs).
Two levels and pricing
| Level | Content | Plan | Pricing |
|---|---|---|---|
| Basic | Verifies the integrity of the challenge response. Catches many simple bots | All plans | Free |
| Deep Analysis | Analyzes thousands of client signals with ML. Handles the most advanced bots | Pro / Enterprise | Pro: $1 / 1000 checkBotId() calls, Ent: custom |
Billing originates from the
checkBotId()call. Passive page views aren't billed. So callingcheckBotId()only on high-value routes is cost-optimal.
Instrumentation: two points, client + server
BotID is two-point instrumentation: "set up the challenge on the client, verify on the server."
// ① クライアント側:保護したいルートのチャレンジを初期化
// app/providers.tsx ("use client")
"use client";
import { initBotId } from "botid/client";
initBotId({
protect: [
{ path: "/api/checkout", method: "POST" },
{ path: "/api/signup", method: "POST" },
],
});
// ② サーバー側:高価値エンドポイントで検証して分岐
// app/api/checkout/route.ts
import { checkBotId } from "botid/server";
export async function POST(request: Request) {
const verification = await checkBotId(); // ← Deep Analysis課金はここで発生
if (verification.isBot) {
return new Response("Forbidden", { status: 403 });
}
// 人間と判定された場合のみ本処理へ
return handleCheckout(request);
}
checkBotId() runs Deep Analysis (when configured) after passing Basic verification and returns the result (isBot, etc.). Put it in only on routes where "being trashed by bots causes damage," like checkout, signup, inquiries, and inventory APIs.
Verified bots, bypass, and observability
- Legitimate bots like search engines can be let through with an allowlist (Verified Bots).
- On a false positive, you can let them through with a WAF bypass rule that detours the BotID judgment.
- BotID checks can be visualized in the Firewall tab's traffic filter or Observability Plus.
Environment variables and OIDC: don't put secrets at the entrance
As important as entrance defense is "not leaking secrets to code/clients."
- Put API keys and DB connection strings into environment variables. The
NEXT_PUBLIC_prefix is exposed to the browser, so don't attach it to secrets (env-leak prevention). - Don't place long-lived access keys for external clouds; obtain temporary credentials keylessly via OIDC.
- On Fluid Compute, don't put user-specific data in global state (preventing tenant crossing; Functions guide).
Production checklist (entrance security)
- DDoS mitigation is working (automatic). Share the Attack Challenge Mode procedure for attacks
- Introduce WAF custom rules in the order observe with Log → escalate
- WAF rate limiting on high-value routes (stop before the function is called)
- Confirm the audit log → instant rollback procedure for false blocks
- BotID on checkout/signup, etc., with
checkBotId()limited to the target routes - Allow legitimate bots, rescue false positives with WAF bypass
- Secrets in environment variables, no secrets in
NEXT_PUBLIC_, external via OIDC - App-layer security (authorization/RLS/injection) designed separately (a WAF can't protect it)
Summary
Vercel's platform-layer security is defense in depth of "broad automatic DDoS mitigation" + "narrow precise WAF" + "BotID that distinguishes human/bot."
- DDoS mitigation is the foundation (automatic on all plans)
- WAF tightens safely via Log→escalate, operated with 300ms propagation and instant rollback
- Rate limiting at the entrance (also protects Active CPU)
- Limit BotID to high-value routes and narrow the billing-originating
checkBotId() - WAF doesn't replace app-layer authorization/injection defense — both wheels
Next, head to the storage, Blob, and Edge Config guide for placing state.
This article is based on the Vercel Firewall / Vercel WAF / BotID official documentation (as of June 2026). Specs, limits, and pricing are updated, so confirm the latest values officially at production adoption.