Peakstack
Contents
Part IV. Shipping13 min read

The demo-to-production gap

Your demo works because you are the only user, you click in the order you designed, your network is fast, and nothing has ever failed. Production is none of those things, and it arrives all at once.

The gap nobody warns you about

There is a moment in every vibe-coded project where the app works. You click through it and it does the thing. It feels finished, and the feeling is not irrational. You have watched every feature succeed with your own eyes.

But you have been running a very particular experiment. One user, who is you. One path, which you designed. One session, which is already authenticated. One network, which is your wifi. Zero failures, because nothing has been asked to fail. The demo is a proof that the happy path exists. Production is everything else, and everything else is most of it.

Stubs that grew up and got a job

To make the UI look right while building, the model generates convincing placeholder content. This is genuinely helpful and you should keep doing it. The problem is that nothing in the toolchain remembers it is fake. To the code, a hardcoded array of testimonials and a real database query are both just data arriving on a page.

app/dashboard/page.tsxVulnerable
// TODO: replace with real data
const stats = { users: 10432, revenue: 89200, growth: 24 };

const testimonials = [
  { name: "Sarah Chen", role: "CTO at Acme", quote: "Changed how we work." },
  { name: "Marcus Webb", role: "Founder", quote: "Couldn't run without it." },
];

This ships. It ships all the time. On launch day it tells your first genuine visitor that you have 10,000 users, which is the exact moment they decide you are not to be trusted.

Go hunting for these specifically. They cluster in predictable places:

  • Dashboards and stats bars. Any impressive number you did not compute from a real query.
  • Testimonials, logos, and avatars. Fabricated social proof is the fastest trust-killer on the internet, worse than having none at all.
  • Empty states. Often the last thing written and the first thing a real user sees, because on day one every state is empty. Your app’s first impression is the screen you spent the least time on.
  • Buttons that go nowhere. Settings, Export, Invite teammates. Rendered, styled, clickable, wired to nothing.
Search your codebase
grep -rn "TODO\|FIXME\|coming soon\|placeholder\|lorem\|dummy\|mock" \
  --include="*.tsx" --include="*.ts" .

# and the one that finds fake numbers:
grep -rn "10,000\|10432\|John Doe\|Jane Smith\|example.com" .

Do this before every launch. It is the cheapest five minutes in this manual.

The promise gap: what your landing page says vs what your app does

This one is structural, and it is the reason this product exists at all. You wrote the landing page early, when you were excited, describing the app you were going to build. Then you built. The plan drifted, as plans do. Features got cut, renamed, postponed.

Nothing anywhere reconciles those two documents. No compiler checks your marketing copy against your routes. Your landing page is, effectively, an unverified claim about software that has since changed without telling it.

So do the reconciliation by hand, at least once. Sit down with your live site and write two columns:

The page promisesThe app actually…Verdict
“Export your data to PDF”Button opens a “coming soon” modalCut the claim, or build the feature
“Real-time collaboration”Polls every 30 secondsReword it honestly
“Bank-level encryption”Uses HTTPS, like every websiteDelete. This one is embarrassing.
“Free forever plan”Hits a paywall at 3 itemsSay what the limit is

Every mismatch is a refund, a bad review, or, at a certain scale and for certain claims, a legal problem. It is also the easiest thing in the world to fix before anyone notices, and impossible to fix gracefully afterwards.

The sad path has never been walked

In development, every request succeeds. It is localhost, it takes four milliseconds, and the database is on your laptop. So the branch where things go wrong is code that has literally never executed, which means it usually does not exist.

Deliberately break your own app. All of these take under a minute:

  • Throttle the network. DevTools, Network, Slow 3G. Now click everything. Is there a loading state, or does the button just sit there while the user clicks it four more times and submits four orders?
  • Go offline mid-action. Start a save, kill the network. Do you get an error, or an eternal spinner?
  • Submit the form twice, fast. Double-charged? Two rows?
  • Paste an emoji, a 10,000-character string, and an apostrophe into every input. The apostrophe finds SQL problems. The emoji finds encoding problems. The long string finds everything else.
  • Hit Back after submitting. Then Forward. Then refresh.

Be user zero, properly

You have never actually experienced your own app. You have a populated account, a live session, and months of context. Your first real user has none of that.

So do this, exactly, and do not shortcut it: open a private window. Sign up with a genuinely new email. Do not skip a step because you know what it does. Go all the way through to the core action.

You will find, almost guaranteed:

  • A verification email that lands in spam, or never arrives at all
  • An empty dashboard with no explanation of what to do next
  • A flow that assumes data you only have because you seeded it by hand
  • An onboarding step that errors because it has never run on a fresh account

Then do it again on your phone, on cellular data. That is where the layout breaks and the 4MB hero image finally announces itself.

The unglamorous things that only matter later

  • Backups. Turn them on. Then restore one, on purpose, to a scratch project. An untested backup is a hope, not a backup.
  • Error tracking. Sentry or similar, ten minutes to install. Without it, production failures are invisible: users do not report bugs, they leave.
  • Rate limits and spend caps on anything that costs money per call. See failure #6.
  • A way to contact you. The single cheapest safety net there is. Someone will find a bug you never will, and right now they have no way to tell you.

When you’re ready to ship

Get an invite to PeakStack.

The demo-to-production gap is, by definition, everything you cannot see from where you're standing: the fake data you stopped noticing, the promise your landing page still makes, the flow that has only ever been walked by someone who already knew the way. PeakStack drives your live app in a real browser, checks what your landing page promises against what the app actually does, and runs the security pass this chapter describes: exposed keys, open database rules, client-side admin gates. You get a letter grade, ranked fixes, and an honest list of what we couldn’t check.

Private beta. Join the waitlist for an invite.