10 November 2026 · 12 min read · BlitzHash · AI & Vibe Coding

Cursor app production checklist: 24 checks before your first customers

Short answer: a Cursor app production checklist comes down to five things you check before your first paying customer signs up. Make sure no secret ever went into Git history, not just the current files. Make sure every API route checks who is calling it. Make sure your live site doesn't serve your .env, your .git folder or secret-shaped strings in its JavaScript. Put a rate limit and a spend cap on anything that costs money per request. And restore a backup at least once. Below are the exact tests we ran on Nov 10, 2026, a probe script you can copy, and a 24-item checklist. If you'd rather have someone walk your app through it with you, start with our production-readiness check for vibe-coded apps.

This guide is for founders who built a web app in Cursor, often with Next.js and a hosted database, and are about to invite real customers. Cursor is very good at writing working features. What it can't know is which parts of your app strangers will poke at, which bills grow with traffic, and what you'll need on the day something goes wrong. That's what this checklist covers. It doesn't repeat our Replit-to-production guide or the 12-check launch scorecard. It focuses on the things that are specific to building in a code editor with an AI agent: your repo, your local files, your terminal and the rules you give the agent.

Why a Cursor app needs its own production checklist

When you build in Lovable or Bolt, the platform owns a lot of the plumbing. When you build in Cursor, you own all of it. The code lives in a Git repo on your laptop. Secrets live in .env files next to the code. The agent can run terminal commands for you. And you choose the host, the database and the deploy pipeline yourself.

That freedom is why many founders pick Cursor, but it moves three risks onto you.

1. The repo becomes a record of every mistake. Anything you ever committed stays in Git history, even after you delete it. 2. The agent sees more than you think. Cursor's own documentation says files in .cursorignore are blocked from the agent's file reading and @-mentions, but that "the terminal and MCP server tools used by Agent cannot block access" to them. If the agent runs cat .env in the terminal, the ignore file doesn't stop it. 3. Nobody reviews the deploy. With no platform in the middle, whatever is on main goes live, including debug routes and test keys.

None of this means Cursor is unsafe. It means a Cursor app production checklist has to look at the repo and your workflow, not only at the live site.

Test 1: does deleting a secret really remove it?

A common story goes like this. Early on, the agent creates a .env file and it gets committed with everything else. Later you notice, add .env to .gitignore, and assume you're covered. We tested that assumption on Nov 10, 2026 with a throwaway Git repo and a fake key.

What we did

1. Created a new repo with an index.js and a .env containing a fake OPENAI_API_KEY=sk-proj-FAKE... value, then committed both. 2. Added .env to .gitignore and committed again. 3. Ran git ls-files to see what Git still tracks, and git check-ignore -v .env to see whether Git treats the file as ignored. 4. Ran git rm --cached .env and committed, which stops tracking the file without deleting your local copy. 5. Searched the whole history with git log --all -p -S 'sk-proj-'.

What we found

  • After step 2, git ls-files still listed `.env`. Adding a file to .gitignore doesn't untrack it. Git's own documentation says it plainly: "Files already tracked by Git are not affected."
  • git check-ignore -v .env printed nothing and exited with code 1, so the file was not treated as ignored while it was still tracked. That's an easy way to get a false sense of safety if you only glance at .gitignore.
  • After git rm --cached, the file dropped out of git ls-files and check-ignore finally reported .gitignore:1:.env.
  • The history search still found the fake key in two commits: the one that added it and the one that removed it. Anyone who can clone the repo, including a future contractor, a leaked laptop or a repo you accidentally make public, can read it.

What to do about it

If a real key was ever committed, rotate it first in the provider's dashboard (OpenAI, Stripe, your database host, email provider). Rewriting history comes second, and GitHub's guide to removing sensitive data explains why: copies may already exist in forks, clones and caches. Then run the same search on your own repo:

git log --all -p -S 'sk_live_' --oneline
git log --all -p -S 'sk-proj-' --oneline
git log --all -p -S 'service_role' --oneline
git log --all --diff-filter=A --name-only --oneline -- '*.env*'

The last command lists every commit that ever added a file whose name contains .env. If any of these print something you didn't expect, treat that secret as burned.

Test 2: a pre-launch probe of your live site

The second test looks at the deployed site from the outside, the way a curious stranger or a bot would. We wrote a small Bash script that sends only read-only GET requests and checks 12 things:

  • Five security headers: Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options, Referrer-Policy and X-Frame-Options.
  • Whether /.env, /.env.local, /.git/config or /.git/HEAD can be downloaded.
  • Whether a made-up page returns a real 404 instead of a 200.
  • Whether the JavaScript files the homepage loads contain secret-shaped strings (sk_live_, sk-proj-, service_role, private key blocks) or point to public source maps.

Here's the core of it. Save it as launch-probe.sh, run chmod +x launch-probe.sh, then run ./launch-probe.sh https://your-domain.com.

#!/usr/bin/env bash
# Pre-launch probe for a Cursor-built web app. Read-only GET requests only.
set -uo pipefail
BASE="${1:?usage: launch-probe.sh https://your-domain.com}"
pass=0; warn=0
ok(){ echo "PASS $*"; pass=$((pass+1)); }
bad(){ echo "WARN $*"; warn=$((warn+1)); }
hdrs=$(curl -sSI --max-time 20 "$BASE/")
for h in strict-transport-security content-security-policy x-content-type-options referrer-policy x-frame-options; do
  echo "$hdrs" | grep -qi "^$h:" && ok "header $h" || bad "missing header $h"
done
for p in /.env /.env.local /.git/config /.git/HEAD; do
  code=$(curl -s -o /tmp/probe.$$ -w '%{http_code}' --max-time 15 "$BASE$p")
  if [ "$code" = "200" ] && grep -Eqi 'API_KEY|SECRET|\[core\]|ref: refs' /tmp/probe.$$; then bad "$p is readable ($code)"; else ok "$p not exposed ($code)"; fi
done
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 "$BASE/this-page-should-not-exist-probe")
[ "$code" = "404" ] && ok "unknown page returns 404" || bad "unknown page returns $code (expected 404)"
html=$(curl -s --max-time 20 "$BASE/")
js=$(echo "$html" | grep -Eo '/_next/static/[^"]+\.js' | sort -u | head -40)
n=0; maps=0; leaks=0
for f in $js; do
  n=$((n+1)); body=$(curl -s --max-time 15 "$BASE$f")
  echo "$body" | grep -q 'sourceMappingURL=' && maps=$((maps+1))
  echo "$body" | grep -Eq 'sk_live_[0-9A-Za-z]{10,}|sk-proj-[0-9A-Za-z_-]{20,}|service_role|-----BEGIN [A-Z ]*PRIVATE KEY' && leaks=$((leaks+1))
done
[ "$leaks" = 0 ] && ok "no secret-shaped strings in $n JS chunks" || bad "$leaks JS chunks contain secret-shaped strings"
[ "$maps" = 0 ] && ok "no public source maps referenced in $n JS chunks" || bad "$maps JS chunks reference source maps"
echo "---"; echo "passed: $pass  warnings: $warn"

The JavaScript check looks for Next.js chunk paths (/_next/static/...). If your app uses Vite or another framework, change that pattern to match the script paths in your page source.

What we found

We ran it twice on Nov 10, 2026.

Against blitzhash.com (a Next.js site on Vercel): 12 passed, 0 warnings. All five headers were present, the .env and .git paths returned 404, the made-up page returned 404, and none of the 10 JavaScript chunks on the homepage contained a secret-shaped string or a source map reference.

Against a deliberately broken local copy that served a .env file, set no headers, and shipped a JavaScript file with a fake key and a source map comment: 4 passed, 8 warnings. The script flagged all five missing headers, the readable /.env, the secret-shaped string and the source map reference.

We ran the second test because a checker that only ever says "all good" proves nothing. You want to see it fail on a known bad site before you trust its pass on yours.

Reading the results

  • A missing header is usually a one-file fix in next.config.js or your host's headers settings. Ask Cursor to add them, then rerun the probe. Start a Content-Security-Policy in report-only mode if you load third-party scripts such as analytics, payments or chat widgets, because a strict policy can break them.
  • A readable `.env` or `.git` path is an emergency. It usually means the whole project folder was uploaded to a plain web server. Take the site down, rotate every key in that file, and redeploy from a build output folder only.
  • A secret-shaped string in JavaScript means a server key reached the browser. It's often a variable with a public prefix such as NEXT_PUBLIC_, or a server-only helper imported into a client component. Our post on leaked API keys in the browser walks through the fix.
  • Source map references aren't a leak by themselves, but they hand your original source code to anyone who asks. Next.js leaves browser source maps off in production unless productionBrowserSourceMaps is turned on, so check that setting first.

What breaks when real customers arrive

The two tests above catch things a stranger can see. The next group only shows up once real people use the app at the same time. These are the questions we ask on every launch review of a Cursor-built app.

Does every API route check who is calling?

Cursor tends to write the page first and the API route second, and the route often trusts whatever the page sends. Open each file under app/api (or pages/api) and ask one question for each: if a logged-out stranger calls this URL directly with someone else's ID, what happens? The quickest real test is to sign up two accounts and try to read account A's data while logged in as B. Our two-account test shows how to do it without writing code.

What happens when someone hits the expensive button 500 times?

Any route that calls a paid API, such as an AI model, email, SMS or image generation, costs you money per call. Without a per-user and per-IP rate limit, one script can run up a bill overnight. Set a spend limit in each provider's dashboard as a second line of defense.

Will the database keep up with real traffic?

AI-written queries often fetch whole tables and filter them in the browser. That's fine with 20 rows and slow with 20,000. Look for list pages without pagination and for queries that run once per item in a loop.

Can you undo a bad deploy and restore yesterday's data?

Find out where your host's "promote previous deployment" or rollback button is before you need it. Then restore a database backup into a scratch project once. A backup you've never restored is a guess, not a plan.

Rules that make Cursor write safer code by default

You can prevent many of these problems at the source. Cursor supports project rules, which are instructions the agent reads on every request. Good rules for a production app say things like: never put secrets in client components, validate every request body on the server, check the session in every API route, verify payment webhooks with the provider's signature, and never log full request bodies. Our free, open-source vibe-coding rules pack installs eight such rules for Cursor and other AI coding tools, and its installer has a dry-run mode so you can see exactly what it writes.

Add your own global ignore patterns too. Cursor's docs suggest **/.env, **/.env.*, **/credentials.json, **/*.key and **/*.pem. Just remember the limit from Test 1: ignore files keep secrets out of the agent's file reading, not out of the terminal or out of Git history. When the agent proposes a terminal command that reads a secrets file, decline it.

The Cursor app production checklist (24 items)

Copy this into your notes and tick each box before your first paying customer.

Repo and secrets

  • ☐ git log --all -p -S finds no live key prefixes (sk_live_, sk-proj-, service_role) in history
  • ☐ git ls-files doesn't list any .env file
  • ☐ Any key that was ever committed has been rotated, not just deleted
  • ☐ .gitignore and .cursorignore both cover .env*, *.pem, *.key and credentials files
  • ☐ The repo is private, and you know everyone who has access
  • ☐ Production keys are set in your host's environment settings, not in a file in the repo

Live site, outside view (run `launch-probe.sh`)

  • ☐ All five security headers are present
  • ☐ /.env, /.env.local, /.git/config and /.git/HEAD return 404
  • ☐ Made-up URLs return a real 404
  • ☐ No secret-shaped strings in the JavaScript files the browser loads
  • ☐ No public source maps, unless you chose to publish them
  • ☐ You ran the probe against a known-bad example first and saw it fail

Access and data

  • ☐ Every API route checks the session before it reads or writes data
  • ☐ The two-account test shows user B can't see or change user A's data
  • ☐ Admin pages check the role on the server, not just by hiding the button
  • ☐ Payment webhooks verify the provider's signature

Cost and abuse

  • ☐ Routes that call paid APIs have per-user and per-IP rate limits
  • ☐ Each paid provider has a spend limit or a billing alert
  • ☐ Signup and contact forms have bot protection

Recovery and operations

  • ☐ You know how to roll back to the previous deployment, and you've tried it
  • ☐ A database backup has been restored into a scratch project at least once
  • ☐ Errors are reported somewhere you'll actually see them, without logging passwords or full request bodies
  • ☐ A smoke test runs after every deploy and fails loudly if the homepage or login breaks
  • ☐ Someone other than you knows where the keys, the host and the domain settings live

If you can tick 20 or more, you're in good shape for a careful launch. If several boxes in "Repo and secrets" or "Access and data" stay empty, fix those first. They're the ones that turn into a customer email you never want to send.

FAQ

Is an app built with Cursor safe for production?

It can be. Cursor writes code, and the code's safety depends on what it was asked to do and what was checked afterwards. The risks in this guide, such as committed secrets, unchecked API routes and missing rate limits, show up in apps from every AI tool and from human developers too. The difference with Cursor is that you own the repo and the deploy, so you also own the checks.

Does .cursorignore keep my API keys away from the AI?

Partly. Cursor's documentation says ignored files are blocked from the agent's code access and @-mentions, and .env* files are on its default ignore list. It also says the agent's terminal and MCP tools can't be blocked this way, and that the protection isn't complete. Keep production keys out of your laptop's project folder where you can, and decline terminal commands that print secrets.

I found an old key in my Git history. Is deleting the file enough?

No. Our test showed the key stays readable in the commit that added it and the commit that removed it. Rotate the key at the provider first, then follow GitHub's guide to removing sensitive data if you also want to clean the history.

How long does this checklist take?

The Git history search and the probe script take a few minutes. The two-account test, rate limits and a backup restore can take an afternoon for a small app, and they're the most valuable part.

Want a second pair of eyes before launch?

If you'd like an engineer to run these checks with you and tell you plainly what's risky, book a free technical assessment through our production-readiness check for vibe-coded apps. You can also start on your own with the free self-check. Either way, you'll come away knowing what to fix before your first customers arrive.

Sources

Related posts

Next step

Book a free 15-min launch review.

A short video call. We look at your AI-built app, flag the biggest risks in security, launch readiness, speed and cost, and you leave with next steps. No obligation.

Every price is a custom quote after we look at the app. No work starts until you accept the proposal.