← All articles

Security

How to Fix Common Bolt.new App Issues: A Complete Repair Guide

12 min read

Updated

Learn how to diagnose and repair the most common performance, security, and database bugs in Bolt.new AI-generated applications.

Bolt.new gets you from idea to working prototype faster than almost anything else. You type a prompt, it scaffolds the entire app, and within minutes you have something running in the browser.

Then real users show up. The page freezes. Deploys fail silently. The database struggles under more than a handful of connections. Performance tanks as data grows.

You are not alone. Security audits of AI-generated projects frequently uncover critical vulnerabilities, showing an average security score of just 52 out of 100 in community-scanned codebases. Across multiple evaluated AI-built apps, developers consistently document security gaps. These bugs reflect predictable patterns that AI application builders produce.

The good news is that these issues break in predictable ways. If you know the patterns, you can fix most problems in an afternoon. This guide walks through the six most common failure categories and exactly how to repair each one.

Common AI-Generated App Problems

Before diving into individual fixes, here is a map of what goes wrong and why. Audits of AI-generated applications report that most MVPs ship with 8 to 14 findings ranging from minor performance issues to critical security gaps.

ProblemRoot causeFrequency
Infinite loops/crashesBad useEffect dependenciesVery common
Failed deploymentsMissing env vars, type errorsCommon
Database errorsConnection pooling, missing indexesCommon
Slow performanceNo pagination, no lazy loadingVery common
Security gapsMissing auth checks, exposed keysVery common
Auth issuesIncomplete session handlingCommon

Even AI-built apps that pass all linters and automated checks can hide real risks once a human reviews them. Audits of production codebases built entirely with AI routinely uncover problems that automated tools miss.

Let's look at how to fix each one.


Fix 1: Infinite Loops and Crashes

This is the single most frustrating bug. Your app works for a few seconds, then the browser tab locks up completely.

  • What is happening: React useEffect hooks trigger on every render because the dependency array is missing or incorrect. The effect updates state, which triggers a re-render, which triggers the effect again. The browser runs this loop until the tab crashes.
  • How to find it: Open Chrome DevTools (F12), go to the Console tab, and look for warnings like "Maximum update depth exceeded" or rapidly repeating log messages.
  • How to fix it:
// BAD: Missing dependency array = runs every render
useEffect(() => {
  fetchData().then(setData);
}); // <-- no [] here

// GOOD: Empty array = runs once on mount
useEffect(() => {
  fetchData().then(setData);
}, []); // <-- runs once

// GOOD: Specific dependency = runs when userId changes
useEffect(() => {
  fetchUserData(userId).then(setData);
}, [userId]); // <-- only re-runs when userId changes

Also check for state updates inside render logic:

// BAD: Setting state during render
function MyComponent({ items }) {
  const [sorted, setSorted] = useState([]);
  setSorted(items.sort()); // This causes infinite loop!

  // GOOD: Use useMemo instead
  const sorted = useMemo(() => items.sort(), [items]);
}
  • Fixing Tip: Ask the AI assistant to "audit all useEffect hooks for missing dependency arrays" to catch the obvious issues. However, do not rely on this alone; a quick manual pass through your hooks is highly recommended.

Fix 2: Failed Deployments

Apps that run fine in the editor sometimes fail to deploy. The build process is stricter than the dev server, and generated code can slip past the looser dev environment.

Common causes and fixes:

  • Missing environment variables: Apps often hardcode values during development that need to be environment variables in production. Run a command to scan for expected environment variables:

    grep -r "process.env" --include="*.ts" --include="*.tsx" src/
    

    Set each one in your hosting platform (Vercel, Netlify, etc.) before deploying. Missing a single variable can cause the build to fail or produce a broken deploy that crashes at runtime.

  • TypeScript errors ignored in dev: The dev server sometimes ignores type errors that the production build step catches. Run npx tsc --noEmit locally to find and fix them before deploying.

  • Import path issues: AI tools sometimes generate case-sensitive import paths that work on macOS (which is case-insensitive by default) but fail on Linux build servers.

    // Fails on Linux: file is actually "UserCard.tsx"
    import { UserCard } from './usercard';
    
    // Fix: match the exact filename case
    import { UserCard } from './UserCard';
    
  • Missing dependencies: Packages may be used in code without being added to package.json. If you see "Module not found" in your build logs, check whether the package is listed in your dependencies.


Fix 3: Database Connection Errors

If your app uses a backend database (like Supabase or Postgres), connection issues typically appear under load. One user hitting refresh works fine, but five concurrent users triggers "Too many connections" errors.

  • Root cause: The generated code creates a new database connection per request instead of reusing a connection pool. Every API route call, server component render, or data fetch opens a fresh connection.

  • How to fix (e.g., Supabase):

    // Create ONE client instance and reuse it
    // lib/supabase.ts
    import { createClient } from '@supabase/supabase-js';
    
    const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
    const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
    
    // Single instance, reused across the app
    export const supabase = createClient(supabaseUrl, supabaseKey);
    

    Then import this single instance everywhere instead of calling createClient in individual files.

  • Missing indexes: Generated schemas rarely include database indexes. Your queries work fine with 50 rows but slow to a crawl with 5,000. Add indexes on columns you frequently filter, sort, or join on:

    -- Add indexes on columns you frequently query or filter by
    CREATE INDEX idx_users_email ON users(email);
    CREATE INDEX idx_orders_user_id ON orders(user_id);
    CREATE INDEX idx_orders_created_at ON orders(created_at);
    
  • N+1 queries: Open your browser DevTools Network tab, load a page that displays a list, and count the requests. If you see one request per list item instead of a single batch request, you have an N+1 query issue. Fix it by fetching related data in a single query with joins or using nested select syntax.


Fix 4: Slow Performance

AI-generated applications tend to load everything at once, which fails as database tables grow.

  • Problem 1: No pagination

    // BAD: Loads every record
    const { data } = await supabase.from('products').select('*');
    
    // GOOD: Paginate
    const { data } = await supabase
      .from('products')
      .select('*')
      .range(0, 19) // First 20 records
      .order('created_at', { ascending: false });
    
  • Problem 2: No image optimization AI utilities often drop basic <img> tags with full-size images, causing list pages to download massive amounts of unoptimized assets. Use Next.js Image or add lazy loading:

    // Replace <img> with lazy loading
    <img src={url} loading="lazy" alt={description} />
    
    // Or use Next.js Image component for automatic optimization
    import Image from 'next/image';
    <Image src={url} alt={description} width={400} height={300} />
    
  • Problem 3: No code splitting Large applications ship all JavaScript in one bundle, forcing the user to download everything upfront. Use dynamic imports for routes and heavy components:

    import dynamic from 'next/dynamic';
    
    const HeavyChart = dynamic(() => import('./HeavyChart'), {
      loading: () => <p>Loading chart...</p>,
    });
    
  • Problem 4: Client-side data fetching for everything By default, data is often fetched on the client side, causing a visible loading spinner on every transition. For data that does not change per user, move the fetch to getServerSideProps or a React Server Component so the page arrives with data already populated.


Fix 5: Security Vulnerabilities

This is where AI-generated code requires the most attention. AI optimizes for making features work, not for locking them down. Audits show that roughly 70% of AI-built apps using backend-as-a-service platforms ship with Row Level Security (RLS) disabled, allowing any user to read, modify, or delete database tables.

  • Missing API route protection:

    // BAD: Anyone can call this endpoint
    export async function POST(request: Request) {
      const data = await request.json();
      await db.insert(data);
    }
    
    // GOOD: Verify authentication first
    export async function POST(request: Request) {
      const session = await getSession(request);
      if (!session?.user) {
        return new Response('Unauthorized', { status: 401 });
      }
      const data = await request.json();
      await db.insert({ ...data, userId: session.user.id });
    }
    
  • Missing input validation:

    // BAD: Trust whatever the client sends
    const { email, amount } = await request.json();
    
    // GOOD: Validate before processing
    const { email, amount } = await request.json();
    if (!email || !email.includes('@')) {
      return new Response('Invalid email', { status: 400 });
    }
    if (typeof amount !== 'number' || amount <= 0 || amount > 10000) {
      return new Response('Invalid amount', { status: 400 });
    }
    
  • Exposed environment variables: Check that no secret keys appear in client-side code. Variables prefixed with client-facing tags (e.g., NEXT_PUBLIC_) are visible in the browser. Service role keys, payment gateway secret keys, and database admin credentials must never be exposed. Use commands to check for leaked credentials:

    grep -r "sk_live\|sk_test\|SUPABASE_SERVICE_ROLE\|password\s*=" --include="*.ts" --include="*.tsx" src/
    
  • Unverified webhooks: If your app processes subscription payments or receives webhooks from an external service, verify the webhook signature before processing. AI builders rarely generate webhook verification code automatically, making it easy to spoof payment events.


Fix 6: Authentication Issues

AI tools handle signup and login UI well, but struggle with session persistence, route protection, and token refresh.

  • No session persistence: Users get logged out on page refresh because the app does not set up a session listener.

    // Ensure session listener runs on app load
    useEffect(() => {
      supabase.auth.getSession().then(({ data: { session } }) => {
        setSession(session);
      });
    
      const { data: { subscription } } = supabase.auth.onAuthStateChange(
        (_event, session) => {
          setSession(session);
        }
      );
    
      return () => subscription.unsubscribe();
    }, []);
    
  • Missing auth guards: Protected pages are often accessible without logging in because the routes lack check wrappers.

    // Wrap protected routes
    function ProtectedRoute({ children }) {
      const { session, loading } = useAuth();
    
      if (loading) return <LoadingSpinner />;
      if (!session) redirect('/login');
    
      return children;
    }
    
  • No token refresh: Sessions expire and the app breaks silently, presenting users with cryptic errors. A proper state listener (like the Supabase script above) resolves this.

  • Missing soft deletes: AI generators default to hard deletes (DELETE FROM), which can create compliance issues and data loss risks. Replace hard deletes with a deleted_at timestamp column and filter deleted records out of your queries.


The Complete App Fix Checklist

Work through this in order. Budget 2 to 3 hours for a full pass.

#CheckEst. Time
1Audit all useEffect hooks for dependency arrays15 min
2Run npx tsc --noEmit and fix type errors20 min
3Search for hardcoded env values, move to .env10 min
4Verify Row Level Security (RLS) is enabled on every table10 min
5Add authentication checks to all API routes20 min
6Add input validation to all form handlers and API routes15 min
7Search for API keys in /src/ files5 min
8Add pagination to all database queries20 min
9Add loading="lazy" to all images10 min
10Add error boundaries to top-level components10 min
11Test auth flow: sign up, login, refresh, logout15 min
12Check for N+1 queries in DevTools Network tab10 min
13Add database indexes on filtered columns10 min
14Verify webhook signatures on payment endpoints10 min
15Run Lighthouse audit, fix critical issues20 min

When to Rebuild vs. Repair

Not every prototype is worth patching. Use this simple test:

Repair if:

  • The core architecture is sound (appropriate database schema, suitable framework).
  • You have fewer than 10 distinct issues to address.
  • The app does what you need, just unreliably.
  • You already have users or data you cannot afford to lose.

Rebuild if:

  • The database schema is fundamentally wrong for your use case.
  • The codebase has grown beyond what you or the AI assistant can manage.
  • You spend more time debugging existing code than building new features.
  • The app handles sensitive payment data and the auth architecture is broken at the foundation.

Tip: Can you explain the data flow of your app from frontend to database and back? If the answer is no, rebuilding with a clearer specification will save you time compared to patching individual issues.


Can AI Fix Its Own Bugs?

For simple, isolated issues, yes. Describe the exact error message and the AI editor will usually generate the right fix.

However, AI self-auditing often misses architectural problems like wrong trust boundaries and access controls. Experiments show that asking an AI to self-audit code before a penetration test still leaves major security vulnerabilities open. AI self-repair tends to add patches on top of patches rather than fix root causes. If you are fixing database schemas, authentication flow, or webhook validation, it is best to export the project to a dedicated code editor (like Cursor) and guide the fixes manually.


FAQ

Why does my app keep crashing?
The most common cause is infinite re-render loops from missing useEffect dependency arrays. Open the Chrome DevTools Console and look for "Maximum update depth exceeded" errors. Fix this by adding the correct dependency array to each useEffect hook.

How do I fix a failed deployment?
Check the build logs. The three most common causes are missing environment variables, TypeScript errors that the dev server ignores but the build step catches, and case-sensitive import paths that break on Linux build servers.

Why is my app so slow?
The app likely loads all data on initial render without pagination. Add limits or ranges (e.g., .range() in Supabase) to database queries, lazy-load images, use dynamic imports for heavy components, and move data fetching to the server side where possible.

Is my app secure enough for production?
Almost certainly not without a manual review. Check API routes for authentication, validate all user input server-side, verify RLS is enabled on every database table, and ensure no secret keys appear in client-side code.

Should I fix my app or rebuild it?
If the core architecture is right and you have fewer than 10 issues, fix it. If the database schema is wrong, the codebase is unmaintainable, or the authentication model is broken at the foundation, rebuild it with a clearer specification.