From AI prototype to production: the eight layers I add, in order
App builders like Lovable, Bolt or v0 get you a working product in days. Then real customers, payments and personal data arrive, and the prototype starts to feel fragile: a small change breaks checkout, nobody knows whether the backups work, and the AI that built it keeps rewriting things. The usual advice is a rewrite. I've taken two such prototypes to production without one. These are the layers I add, in this order, and why the order matters.
Updated 11 min read
1. Take stock in one afternoon
Export the code to GitHub if it isn't there yet, and write down what the app actually does: sign-up and login, payments, emails, file uploads, admin screens, scheduled jobs, AI calls. Mark everything that touches money or personal data. That list is your risk map, and it is usually shorter and clearer than people fear.
Then check where the secrets live. In generated apps they often end up in the frontend code, a shared .env file or a chat history with the AI builder. Look at the database too: which tables exist, which have no access policies, which columns hold personal data. The readiness check below turns this afternoon into a score, so you can see at a glance where to start and show progress later.
Tip from practice
Search the built JavaScript bundle for your service-role key or payment secret. If it's there, rotate it today, before anything else on this list.
Interactive
Is your AI-built app ready for production?
Tick what is already true. The gaps that are left are your to-do list, in order.
Your next three steps
- Code lives in Git; changes go through pull requests
- No secret keys in the frontend; server keys only on the server
- Row-level security (or equivalent) on every table
2. Separate staging and production
Two environments with their own database, their own keys and their own third-party accounts in test mode. Every change goes through staging first, database migrations included, and nothing reaches production that hasn't run there. With Supabase, a second project or branching gives you a staging database; on Vercel, preview deployments give every pull request its own URL to click through.
This single step removes most of the 'it broke on the live site' moments, because the AI builder and the developers now have a place to be wrong safely. Keep staging close to production: same configuration, same extensions, realistic but anonymized data. A staging environment that drifts becomes a place where everything works and nothing proves anything. The Supabase production checklist is a good companion here: it walks through the settings that differ between a hobby project and a live one, from network restrictions to email providers.
3. Lock down who can read what
Generated code often trusts the browser: the frontend hides a button and assumes that's security. Production needs the database to enforce it, because anyone can call your API without your frontend. Turn on row-level security on every table, write policies per role, and repeat the critical checks in server-side functions. Broken access control has topped the OWASP Top 10 for years, and AI-built apps are no exception.
Then write one test per role that tries to read and write data it shouldn't: another organisation's invoices, an admin setting, a deleted user's records. These tests are cheap to write and priceless when the AI changes a policy without telling you. In one platform this meant policies on every table and a test suite that grew past a thousand files, and that suite is what lets the team keep shipping fast.
-- Members only see invoices of their own organisation
alter table invoices enable row level security;
create policy "members read own org invoices"
on invoices for select
using (
org_id in (
select org_id from memberships
where user_id = auth.uid()
)
);Tip from practice
A policy you haven't tested is a guess. In your test suite, log in as each role and try to read another organisation's data; the test passes only if the database says no.
4. Backups you have restored
The hosting provider's backups are a start, not a plan. If the account is locked, the region has an outage or someone deletes the project, those backups go with it. Add encrypted dumps on a schedule, stored with a different provider, and restore one into a separate project every night with a check that the row counts match. Uploaded files need the same treatment: mirror them to a second object store.
The reliability pillars of the Azure and AWS Well-Architected Frameworks both ask the same uncomfortable question: when did you last test a restore? In the production platforms I run, the restore test runs every night, and it is the only reason I can say the backups work. A backup you have never restored is a hope, not a plan, and you don't want to find that out during an incident.
# Nightly: dump, encrypt, ship to another provider, prove it restores
pg_dump "$PROD_DB_URL" --format=custom --file=prod.dump
age -r "$BACKUP_PUBKEY" -o prod.dump.age prod.dump
aws s3 cp prod.dump.age "s3://backups-offsite/$(date +%F)/" \
--endpoint-url "$OFFSITE_S3_ENDPOINT"
pg_restore --clean --if-exists --no-owner -d "$RESTORE_TEST_DB_URL" prod.dump
psql "$RESTORE_TEST_DB_URL" -c "select count(*) from public.bookings;"5. A release pipeline that can say no
Pull requests only, no direct pushes to main, not even for the AI. CI runs type checks, linting with a baseline that may only improve, unit tests, and a dry run of database migrations against staging before anything merges. A migration that fails on staging at 3 p.m. is a learning; the same migration failing on production at 3 a.m. is an incident.
After the merge, deploy only what changed and run a smoke test against the live site: can someone sign up, log in and reach checkout? If not, roll back automatically or with one click. Small, reversible steps add up faster than big careful ones: one platform shipped 3,025 merged pull requests in ten months this way, and the pipeline is what made that pace safe.
# .github/workflows/ci.yml (excerpt)
on: pull_request
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22 }
- uses: supabase/setup-cli@v1
- run: npm ci
- run: npm run typecheck && npm run lint && npm test
- name: Migration dry run against staging
run: supabase db push --dry-run --db-url "$STAGING_DB_URL"
env:
STAGING_DB_URL: ${{ secrets.STAGING_DB_URL }}6. Monitor what customers actually do
CPU graphs don't tell you that nobody could book since lunch. The Google SRE book puts it simply: monitor the symptoms users feel, not just the causes. Add outside-in checks on the journeys that matter, sign-up, checkout and booking, every few minutes from outside your hosting, so you hear about a broken flow before a customer writes to you.
Then watch business states, not just technical ones. 'Payment succeeded but no booking was created' and 'no bookings in six hours on a weekday' are the alerts that catch the expensive bugs. On one platform that meant hourly probes on the booking funnel, a daily synthetic payment and a booking-drought alert. Alert on state changes only, open and resolved, so people keep reading the alerts instead of muting the channel.
Tip from practice
Run one synthetic payment a day through the real checkout in test mode. It catches broken webhooks long before a customer does.
7. Secrets and access without long-lived keys
Move secrets out of the code, out of chat histories and off people's laptops. Each environment gets its own secrets in the platform's secret store. CI authenticates to your cloud with OpenID Connect instead of stored keys, so there is no long-lived credential in GitHub that could leak. Service-role keys stay on the server and never reach the browser.
Access for people follows the same idea. Everyone gets their own account with the least rights they need, admins use multi-factor authentication, and access is removed the day someone leaves. Write it down in a one-page access matrix: who can deploy, who can read production data, who can change billing. It takes an hour, and it answers the first questions of every customer security questionnaire you'll ever receive. Review it every quarter; access that nobody looks at only ever grows.
8. Guardrails for the AI that keeps building
The coding agent that built the prototype will keep changing it, so give it rules, the same way you would onboard a new developer. A written instruction file in the repository says what it may and may not touch, which commands it must run before a pull request, and which areas always need a human: login, payments, deleting data, access policies.
Keep its pull requests small, and make it prove its work. A real-browser check of the main journeys before each release, a screenshot or test result in every pull request that changes a user flow, and a human approval for the sensitive areas. The agent keeps its speed; the pipeline, the tests and the review keep production safe. That combination is the whole point: you get the pace of an AI-built product with the reliability customers expect from a real one.
Tip from practice
Make the agent prove it: no pull request that touches a user journey merges without a browser test result or a screenshot attached.
Takeaway
Keep the speed of the prototype and add the safety of production in layers. You don't need a rewrite; you need these eight steps, in this order.
Real projects behind this
Try it yourself
Sources and official guides
More articles
- 3,025 pull requests in ten months: an AI-assisted delivery process, from the inside
- The EU AI Act for mid-sized companies: what applies to you, and when
- FinOps for AI spend: tokens, caching, routing and budgets that hold
- Making a restaurant network visible in AI answers: a GEO project, step by step
- How this site is built: static where it can be, streaming where it must
- Kubernetes cost on EKS and GKE: the same playbook, different levers
- A landing zone for mid-sized companies, in Terraform or Bicep: the parts that matter
- The legacy migration playbook: waves, parallel runs, and identical row counts and checksums
- MCP security in depth: how to let AI assistants into your product without opening the doors
- Monitoring on business outcomes: green dashboards, empty checkout
- Phone AI agents: the architecture, and the pitfalls nobody shows in the demo
- Restore tests: a backup you have never restored is only a hope
- Streaming AI answers on Azure Static Web Apps: the one header that buffered everything
- Building an AI assistant for WhatsApp, end to end: what it takes beyond the demo
- Air-gapped systems: running critical software with no internet
- Production AI on AWS: Amazon Bedrock and AgentCore in a private setup
- Production AI on Microsoft Foundry: a private reference setup for agents
- /goal, /loop or routines: stop babysitting your coding agent
- Claude's new plans: Max, Ultra and what they mean for teams
- OpenAI Codex at the end of 2026: goal mode, dots and how to lock it down
- GitHub Copilot, Claude Code or Codex? How I'd choose for a company
- GEO basics: how to show up in AI answers
- Production AI on Google Cloud: from Vertex AI to Gemini Enterprise Agent Platform
- Local LLMs in an air-gapped network: AI for your most sensitive data
- I want to run a local LLM: which server should I buy?
- MiniMax M3: an open frontier model you can run yourself?
- Prompt research at scale with an open model
- SEO and GEO together: a practical audit in 6 steps
- Right-size Kubernetes: the playbook that took a cluster from 7 to 4 nodes
- Private AI for sensitive data: a local LLM setup that passes the security review
