Ship Safely on Vercel with Flags and WAF

Deploy a Next.js app with feature flags, preview environments, and WAF rules.

Introduction

30 Second Summary

Every app update carries risk. Professional teams never flip a switch and hope for the best. They test features in isolated environments, roll them out gradually, and block malicious traffic before it reaches users.

In this project, you will use Vercel's platform tools to ship features safely. You'll configure feature flags that behave differently across environments, deploy to preview and production simultaneously, and set up WAF rules to protect your app from bad traffic.

What You'll Build

A deployed application on Vercel that demonstrates the professional "ship safely" workflow using feature flags, preview deployments, and firewall custom rules.

By the end of this project, you'll have:

  • A feature flag configured per-environment in the Vercel Dashboard, toggled live without redeploying.
  • A preview deployment and a production deployment running side by side with different flag behavior from the same code.
  • WAF custom rules protecting your production site with path blocking, rate limiting, and IP blocking.
  • Secret Mission: Configure a progressive rollout that gradually enables a feature for production traffic.

Are there any prerequisites?

You should already have a Vercel account, a GitHub account, Node.js installed, and the Vercel CLI installed. You'll also need a coding agent like Claude Code or Codex running in Cursor.

Vibe Code the App and Set Up Flags

Professional teams never deploy features directly to production. They use feature flags to control what users see across different environments. A flag can be ON in testing but OFF in production, giving you a kill switch for any feature.

In this step, your coding agent handles the app code while you focus on the platform. You will scaffold a Next.js app with the Flags SDK, create a feature flag in the Vercel Dashboard, and confirm it works locally.

In this step, get ready to:
  • Prompt your coding agent to scaffold a Next.js app with feature flag integration.
  • Create and configure a boolean feature flag in the Vercel Dashboard.
  • Pull environment variables locally and verify the flag works with Flags Explorer.
Prompt your agent to scaffold the app

Your coding agent will create the entire Next.js application for you. The key packages it needs to install are flags (the Flags SDK) and @flags-sdk/vercel (the adapter that connects to Vercel Flags).

  • Open your coding agent (Claude Code or Codex in Cursor).
  • Give your agent the following prompt:
Create a Next.js app with the following:
- Install the `flags` and `@flags-sdk/vercel` packages
- Create a flag definition file that defines a boolean flag called `new-feature` using `vercelAdapter()`
- Create a page that evaluates the flag and conditionally renders a "New Feature" section when the flag is true
- Include the Vercel Toolbar for local development so I can use Flags Explorer
- Set up a Flags Discovery Endpoint at the well-known path so Flags Explorer can detect my flags

What is the agent building?

The flags package is Vercel's Flags SDK. It provides a framework-native way to define and evaluate feature flags in Next.js.

The @flags-sdk/vercel package is the adapter. Its vercelAdapter() function reads from the FLAGS environment variable automatically, connecting your app to the flag values configured in the Vercel Dashboard.

  • Wait for the agent to finish scaffolding.
  • Initialize a Git repository and push the project to GitHub by running:
git init
git add .
git commit -m "Initial commit with flags SDK"
git remote add origin [[YOUR_REPO_URL="https://github.com/your-username/your-repo.git"]]
git branch -M main
git push -u origin main
  • Link your local project to Vercel by running:
vercel link

The CLI will ask you to confirm the project. Follow the prompts to connect your local folder to your Vercel account.

Agent didn't install the right packages?

Make sure your prompt explicitly names flags and @flags-sdk/vercel as the packages to install. If the agent used a different flag library, ask it to replace with these specific packages.

If vercel link fails, confirm you are authenticated with the Vercel CLI. Run vercel whoami to check.

Help me troubleshoot my Vercel Flags SDK setup.

Create the feature flag in the Vercel Dashboard

Now that your project is linked, you will create the flag on the platform side. The Vercel Dashboard is where you control flag values per environment without touching code.

  • Open the Vercel Dashboard in your browser.
  • Select your project.
  • Click Flags in the sidebar.
  • Click the Create Flag button.
  • Enter new-feature as the Slug.
  • Leave the Type set to Boolean.
  • Configure the environment settings: set Development to ON, Preview to ON, and Production to OFF.
  • Click Review and save.

What is Vercel doing behind the scenes?

When you create your first flag, Vercel automatically provisions two environment variables for your project: FLAGS and FLAGS_SECRET. The FLAGS variable contains SDK Keys that map each environment (Development, Preview, Production) to its own flag configuration.

This means the same code deployed to Preview reads the Preview SDK Key and gets ON, while the same code deployed to Production reads the Production SDK Key and gets OFF. No code changes required.

Why ON for Preview but OFF for Production?

This pattern mimics how professional teams ship features. Preview deployments let you test the full feature before releasing it. Production stays safe with the flag OFF until you explicitly toggle it on from the dashboard.

Don't see the Flags section in the sidebar?

Make sure you are viewing your project settings, not the team overview. Click your project name from the dashboard first, then look for Flags in the left sidebar.

Help me find the Flags section in my Vercel Dashboard.

Pull environment variables and test locally

The FLAGS and FLAGS_SECRET variables live on Vercel's servers. You need to pull them into a local .env.local file so your app can read them during development.

  • Download the environment variables by running:
vercel env pull

What does this command do?

This saves your project's environment variables (including FLAGS and FLAGS_SECRET) to a .env.local file in your project root. Next.js automatically reads this file during local development.

  • Start the development server by running:
npm run dev
  • Open http://localhost:3000 in your browser.
  • Confirm the "New Feature" section is visible on the page. The Development environment flag is ON, so the section renders.

Now open the Flags Explorer to see your flag in action.

  • Look for the Vercel Toolbar floating at the bottom of your browser window.
  • Click the toolbar and select Flags Explorer from the menu.
  • Find the new-feature flag listed. You can override its value here to test how the page looks with the flag OFF.
  • Toggle the flag to false and apply. The page soft-reloads and the "New Feature" section disappears.
  • Toggle it back to true and apply to restore it.

What is Flags Explorer?

Flags Explorer is built into the Vercel Toolbar. It lets you view and override feature flags directly in your browser without affecting other users or environments. Overrides apply only to your current session.

When you apply an override, the toolbar turns blue to indicate active overrides are in effect.

Don't see the Vercel Toolbar?

The toolbar only appears when the app is configured to include it during local development. Check that your agent set up the @vercel/toolbar package and conditionally renders the VercelToolbar component in your layout file.

Also confirm that vercel link was run successfully. The toolbar needs the project to be linked to display.

Help me get the Vercel Toolbar working locally.

Your flag evaluates to true locally and you can override it on the fly. Next up, you will deploy to both Preview and Production to see the same flag behave differently across environments without changing any code.

Deploy to Preview and Production

Your flag is configured and working locally. Now it is time to see the real power of environment-aware flags: deploying the same code to two different environments and watching it behave differently.

Vercel provides separate Preview and Production environments. Each environment uses its own SDK Key, which tells the Flags SDK which configuration to load. You will deploy to both and confirm the flag respects its per-environment settings without changing a single line of code.

In this step, get ready to:
  • Deploy a preview and confirm the feature flag is ON.
  • Deploy to production and confirm the feature flag is OFF.
  • Toggle the production flag live from the dashboard without redeploying.
Deploy to preview

A preview deployment is a live version of your app that uses preview environment variables. It is perfect for testing features before they reach production.

  • Create a preview deployment by running this command in your project folder:
vercel

What does this command do?

Running vercel without any flags deploys your project to the Preview environment. The CLI builds your app, fetches the flag definitions using the Preview SDK Key, and outputs a live URL when the deployment finishes.

  • Wait for the deployment to finish. The CLI prints a Deployment URL in the terminal output.
  • Copy the preview URL from the terminal output.
  • Open the preview URL in your browser.

You should see the "New Feature" section visible on the page. The Preview SDK Key resolves the new-feature flag as ON because you configured Preview to be ON in the previous step.

Why does the same code show the feature here?

When Vercel builds a preview deployment, it injects the Preview SDK Key into the FLAGS environment variable. Your app's vercelAdapter() reads this key, connects to the Preview configuration, and evaluates new-feature as true.

Don't see the New Feature section?

Make sure the deployment finished successfully. Check the terminal for any build errors.

Confirm that your new-feature flag is set to ON for the Preview environment in the Vercel Dashboard. If it was still set to OFF, change it to ON, then redeploy with vercel again.

Help me figure out why my preview deployment isn't showing the feature flag as enabled.

Deploy to production

Now deploy the exact same code to production. The only difference is the SDK Key that Vercel injects at build time.

  • Deploy to production by running this command:
vercel --prod

What does --prod change?

The --prod flag tells Vercel to deploy to the Production environment instead of Preview. The build process uses the Production SDK Key, which means your flag evaluates against the Production configuration.

  • Wait for the deployment to finish. The CLI prints your production URL.
  • Copy the production URL from the terminal output.
  • Open the production URL in your browser.

The "New Feature" section is hidden. The Production SDK Key resolves the new-feature flag as OFF because you configured Production to be OFF.

Same code. Two URLs. Different behavior. The flag is the only thing that changed between the two deployments.

Still seeing the feature on production?

Double check that the new-feature flag is set to OFF for the Production environment in the Vercel Dashboard.

If you recently changed the flag value, you need to redeploy with vercel --prod because flag definitions are embedded at build time.

Help me debug why my production deployment is still showing the feature.

Toggle the production flag live from the dashboard

Here is the real magic of feature flags. You can change what production users see without pushing code or redeploying. The flag configuration propagates globally within 300ms.

  • Return to the Vercel Dashboard.
  • Open **Flags** in the sidebar for your project.
  • Click on the new-feature flag to open its configuration.
  • Select the **Production** environment.
  • Change the value from false to true.
  • Click **Review and save**.
  • Leave a change message (for example, "Enabling new feature for production") and confirm.

What happens when you save?

Vercel propagates the new flag value globally. The next time your production deployment evaluates the flag, it reads the updated configuration. No redeploy needed because the SDK fetches the latest flag state at runtime for server-rendered pages.

  • Reload your production URL in the browser.

The "New Feature" section now appears on production. You toggled a live feature for all production users from the dashboard in seconds.

Feature not appearing after toggling?

Make sure you clicked **Review and save** and confirmed the change. The flag update only takes effect after you confirm in the modal.

Try a hard refresh in your browser (Cmd+Shift+R on macOS or Ctrl+Shift+R on Windows) to bypass any cached response.

Help me figure out why my production flag toggle isn't taking effect.

You have proven the core workflow: deploy behind a flag, test in preview, ship to production hidden, then reveal when ready. Next up, you will protect your production deployment with WAF rules and rate limiting.

Configure WAF Rules and Rate Limiting

Your app is deployed and feature flags are controlling visibility across environments. The next layer of a professional deployment is security.

Attackers constantly probe production sites for exposed config files like .env and .git. They also hammer API endpoints with automated requests. In this step, you will configure Vercel's WAF (Web Application Firewall) to block these common attacks without writing any code.

In this step, get ready to:
  • Create a custom WAF rule that blocks requests to sensitive file paths.
  • Set up rate limiting on your API route to prevent abuse.
  • Use the Vercel CLI to create firewall rules with natural language.
Block sensitive file paths with a custom rule

Bots routinely scan websites for files like .env (environment variables), .git (source control), and .bak (backup files). A single WAF rule can deny all of these requests at the edge before they ever reach your application.

  • In the Vercel Dashboard, open your project and click Firewall in the left sidebar.
  • Click the ... menu at the top right of the Firewall overview page.
  • Select Configure.
  • Click Add New... and select Rule.
  • In the name field, type Block sensitive paths.
  • In the Configure section, set the first If condition to: Path ends with .env.
  • Click the OR operator to add a second condition: Path ends with .git.
  • Add a third OR condition: Path ends with .bak.
  • For the Then action, select Deny.
  • Click Save Rule.
  • Click Review Changes at the top right.
  • Click Publish to apply the rule to your production deployment.

What does this rule do?

This rule evaluates every incoming request at Vercel's edge network. If the request path ends with .env, .git, or .bak, the request is immediately denied with a 403 response.

The OR operator means any one of the three conditions triggers the block. Changes apply globally within 300ms.

  • Test the rule by visiting your production URL with /.env appended to the end.
  • You should see a 403 Forbidden response instead of your normal page.

Still seeing your normal page?

Make sure you clicked Publish after Review Changes. Rules that are only saved but not published do not take effect.

Also confirm you are visiting your production URL, not your preview URL. WAF rules apply to production deployments.

Why is my WAF rule to block .env paths not working?

Set up rate limiting on your API route

Rate limiting prevents a single IP address from overwhelming your API with requests. On the Hobby plan, you get 1 rate limiting rule per project with up to 1,000,000 allowed requests included.

  • Return to the Firewall Configure page.
  • Click Add New... and select Rule.
  • Name the rule Rate limit API.
  • In the Configure section, set the If condition to: Path starts with /api.
  • For the Then action, select Rate Limit.
  • Set the Time Window to 60 seconds.
  • Set the Request Limit to 10 requests.
  • Leave the counting key as IP (the default).
  • Click Save Rule.
  • Click Review Changes, then Publish.

What does rate limiting do here?

This rule counts requests from each IP address to any path starting with /api. If a single IP sends more than 10 requests within a 60-second window, subsequent requests receive a 429 (Too Many Requests) response.

The fixed window algorithm resets the counter every 60 seconds. This stops automated scrapers and brute-force attacks from overwhelming your API.

  • Test rate limiting by sending rapid requests to your production API endpoint. Run this in your terminal:
for i in $(seq 1 15); do curl -s -o /dev/null -w "%{http_code}\n" [[PRODUCTION_URL="your-production-url"]]/api/data; done

What does this command do?

This loop sends 15 requests to your /api/data endpoint and prints only the HTTP status code for each response. The first 10 requests should return a normal status code. After the limit is hit, you should start seeing 429 responses.

You should see the first several responses return a normal status code, then the remaining responses return 429.

All responses returning 200?

Make sure you published the rate limit rule. Also verify you are targeting your production URL, not localhost or a preview URL.

If you just published, wait a few seconds for propagation. Vercel applies WAF changes globally within 300ms, but the very first request after publish may still pass through.

Help me debug my rate limiting rule

Create a rule with the Vercel CLI (alternative)

The Vercel CLI can generate firewall rules from a natural language description. This is useful for quickly iterating on rules without switching to the dashboard.

  • Create a firewall rule using natural language by running this command:
vercel firewall rules add --ai "Block requests where path ends with .env, .git, or .bak"

What does this command do?

The --ai flag tells the Vercel CLI to interpret your natural language description and generate the matching rule conditions and action. It creates the same deny rule you built manually in the dashboard.

The CLI will show you the generated rule for review before applying it. You can accept it as-is or edit the conditions.

When to use CLI vs Dashboard

The dashboard gives you a visual builder and traffic monitoring in the same view. The CLI is faster when you already know what rule you want and prefer to stay in the terminal. Both produce the same result.

Your production deployment is now protected by two WAF rules. Sensitive file paths are blocked and your API endpoint is rate-limited. Next, you will take IP blocking further and explore the Firewall monitoring tools.

Block IPs and Monitor Firewall Traffic

Your production site is now protected by path-blocking rules and rate limiting. The next layer of defense is even more direct.

IP blocking lets you cut off a specific actor entirely. In this step, you'll block your own IP to see exactly what an attacker experiences, monitor the blocked traffic in the Firewall dashboard, and learn how to reverse any firewall change instantly.

In this step, get ready to:
  • Block your own IP address from accessing your production site.
  • Confirm the block by observing the 403 Forbidden response.
  • Monitor blocked traffic in the Firewall log and restore your access.
Find your public IP and create a block rule

To block yourself, you first need to know your public IP address. This is the address Vercel's firewall sees when you visit your site.

  • Open a new browser tab and search for "what is my IP" in Google.
  • Copy the IP address displayed at the top of the results. It will look something like 203.0.113.42.
  • Return to the Vercel Dashboard and open the Firewall section in the sidebar of your project.
  • Click Configure on the top right of the Firewall overview page.
  • Scroll down to the IP Blocking section.
  • Click + Add IP.
  • In the IP Address Or CIDR field, paste the IP address you copied.
  • In the Host field, enter your production domain without the https:// prefix. You can copy this from your production URL.
  • Click Create IP Block Rule.
  • Click Review Changes in the top right corner.
  • Review the pending change, then click Publish to apply it to your production deployment.

What is IP blocking?

IP blocking is the most direct WAF action. It denies all requests from a specific IP address before they ever reach your application. The request never touches your code, your serverless functions, or your CDN traffic.

Vercel supports up to 10 project-level IP blocks on the Hobby plan. Changes propagate globally within 300ms.

Why use the production domain as the Host?

The Host field tells Vercel which domain to apply the block to. You must enter the exact domain you want to protect without the https:// prefix. If your production URL is my-app.vercel.app, that is what you enter.

Test the IP block on your production site

With the rule published, your own IP is now blocked from accessing the production domain. Time to see it in action.

  • Open a new browser tab (or use the same one).
  • Visit your production URL.
  • You should see a 403 Forbidden response instead of your app.

This is exactly what an attacker or malicious bot would see if you blocked their IP address. The request is denied at the edge and never reaches your application.

Still seeing your app instead of 403?

  • Make sure you clicked Publish after creating the rule. Unpublished rules are staged as drafts and do not take effect.
  • Verify the Host field matches your production domain exactly. If your production URL includes a subdomain (like www), include it.
  • Try opening the URL in an incognito window to bypass any browser cache.

Help me troubleshoot my IP block rule.

Monitor blocked traffic and remove the rule

Now that you've confirmed the block works, check the Firewall traffic log to see the denied request. Then remove the block to restore your own access.

  • In the Vercel Dashboard, click Firewall in the sidebar to return to the Firewall overview page.
  • Look at the Denied IPs section on the overview. You should see your IP address listed as a blocked source.
  • The Rules section shows which rule handled the traffic. Your IP block rule should appear here with associated events.

What does the Firewall overview show?

The Firewall overview page provides a consolidated view of all traffic and events. It includes a traffic chart, an Alerts section for detected attacks, a Rules breakdown showing which rules handled traffic, an Events section for individual mitigation actions, and a Denied IPs list showing the most commonly blocked sources.

You can also click Traffic in the sidebar to drill down into requests grouped by Client IP, User Agent, Request Path, or Country.

Now remove the block to restore your access.

  • Click Configure on the top right of the Firewall overview page.
  • Scroll down to the IP Blocking section.
  • Delete your IP block rule by clicking the delete icon next to it.
  • Click Review Changes in the top right.
  • Click Publish to apply the change.
  • Visit your production URL again. Your app should load normally now that the block is removed.

What is the Audit Log and instant rollback?

Every firewall change you publish is recorded in the Audit Log. You can access it from the Firewall sidebar. If you ever need to undo a change quickly, select a previous version by date and time, click Restore, then click Restore Configuration to instantly roll back to that state.

This is useful in production emergencies where a misconfigured rule is blocking legitimate traffic. You can revert to a known-good configuration in seconds.

Still blocked after removing the rule?

  • Confirm you clicked Publish after deleting the rule. Removing a rule without publishing leaves it in draft.
  • Try a hard refresh in your browser (Cmd+Shift+R on macOS or Ctrl+Shift+R on Windows) to clear any cached 403 response.
  • If issues persist, use the Audit Log to restore a previous firewall configuration.

Help me restore access to my production site after removing an IP block.

Secret mission

Progressive Rollout

Instead of toggling your feature flag on for everyone at once, configure a progressive rollout that gradually enables it for production traffic over time. This is how professional teams de-risk feature launches. You will set up a time-based schedule that ramps up the percentage of users who see the new feature.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely on Vercel's free Hobby plan, so there are no ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Resources you used:

  • Vercel project (includes deployments, feature flag configuration, and WAF rules).
  • GitHub repository (Next.js app with Flags SDK integration).
  • Local project files and .env.local file.

Keep everything running

No action needed. Choose this if you are still actively building or want the preview and production deployments to stay live.

  • Your project stays deployed on the free Hobby plan at no cost.
  • WAF rules remain active and protecting your production deployment.
  • The feature flag configuration and progressive rollout continue running.

Pause - I'll come back to this later

Disable your WAF rules without deleting them. This frees up your rule slots if you want to use them on another project.

  • In the Vercel Dashboard, open your project's Firewall section.
  • Click Configure and disable or delete each custom rule.
  • Your deployments stay live, but traffic is no longer filtered.
  • The feature flag remains configured in the dashboard. You can re-enable WAF rules any time you return.

Delete - I don't want to use this again

Remove all project resources and start fresh. This permanently deletes your deployments, flag configuration, WAF rules, and environment variables.

  • Delete the Vercel project:
  • Delete the GitHub repository:
  • Delete local project files by running this command:

That's a Wrap!

That's a Wrap!

Nice work! You just shipped a full "deploy safely" workflow on Vercel. Your app has environment-aware feature flags, separate preview and production deployments, and firewall protection. All without writing infrastructure code yourself.

You've learned how to:

  • Created and configured a feature flag with per-environment settings, deploying to both Preview and Production to observe different behavior from the same code.
  • Toggled a flag live from the Vercel Dashboard without redeploying, proving zero-downtime feature control across environments.
  • Protected your production deployment with WAF custom rules, rate limiting, and IP blocking. You tested each rule and used the Firewall traffic log and instant rollback features.
  • Secret Mission: Configured a progressive rollout to gradually enable a feature for production traffic over time, rather than toggling all-at-once.

Ready to quiz yourself?