← Resources · One Pager · Prompt Oct 23, 2026
Find The Slow Parts

Speed Audit

AI writes code that works. It doesn't always write code that's fast. Most slow vibe-coded apps are slow for the same dozen reasons, and none of them show up until you have real data. Here's the list, how to spot each one, and one prompt that makes your agent hunt for them in your own codebase.

How To Use This Page

In a hurry? Copy The Prompt into Claude Code and let it look. Want to understand what it finds? Start with The Database.

12
Bottlenecks To Check
1
Prompt To Find Them
$0
Free, Copy And Go
Fast Enough?

A Fast App Still Needs Customers.

Speed keeps the users you have. It doesn't bring you new ones. Shaving a second off a page nobody visits is Building Theater: it feels like progress and it makes $0.

The Solo Founder Lab · Opening Soon

I'm building a place where you learn to build products that work like a real company's on your own, and get them in front of people who pay, with a CTO who's built two seven-figure software companies in your corner.

Lab.exeWaitlist Open

Build Fast. Sell Faster.

  • Live product teardowns. Your app, your landing page and your pricing, reviewed in front of everyone.
  • Weekly CTO office hours. Live, hot-seat style. Bring the slow page you're stuck on.
  • Launch Pad. When you launch, the room shows up.
  • The 30-Day Launch Plan. Validate, plan, build and launch, one week at a time. Members only.

Free to join the waitlist. Opens at $49/mo, and the price goes up as seats fill, so first in pays the least.

Why It Happens

Works On 12 Rows. Dies On 12,000.

The Short Version

Your agent writes the simplest code that works on the data in front of it. With a dozen test rows, a query inside a loop is instant and doing things one at a time is fine. Nobody notices until real customers show up, and then the page takes ten seconds and the server bill doubles.

The Good News

The mistakes repeat. Almost every slow app I look at has two or three of the twelve below. And the same agent that wrote them is very good at fixing them, once you tell it what to look for.

Story.Log✣

Years ago, before AI, a company I worked with pulled sales data from thousands of retail stores. The system processed it one day at a time: finish Monday, then start Tuesday.

It crashed constantly, nobody could see its progress, and adding servers didn't help. One Friday I was asked to babysit a run all weekend. I spent the weekend replacing it instead: every day became its own job in a queue, and several machines worked through it in parallel.

Before
72–96 hrs
After
A few hours
Saved
~$3,000/mo
The Database

Where Most Of The Time Goes

If a page is slow, check the database first. Every trip to it costs time, and AI-written code tends to make a lot of trips.

01 · N+1 QueriesDB

One query for the list, then one more for every item in it.

You load 100 orders, then loop through them and look up each customer. That's 101 trips to the database for one page. It's the most common slowdown in AI-built apps, and it hides inside friendly-looking ORM code.

// Slow: 1 query + 1 per order
const orders = await db.order.findMany();
for (const o of orders) {
  o.customer = await db.customer.findUnique({
    where: { id: o.customerId },
  });
}

// Fast: one query that brings the customers along
const orders = await db.order.findMany({
  include: { customer: true },
});
Spot It
Turn on query logging and load the page. Dozens of near-identical queries in a row means N+1.
Fix
A join, an include, or one WHERE id IN (...) query for the whole list.
02 · Missing IndexesDB

The database reads every row to find the five you asked for.

An index is the database's table of contents. Without one on the columns you filter and sort by, every lookup is a full scan. Fine at 1,000 rows, painful at a million. Postgres doesn't index foreign keys for you, so user_id columns are a classic miss.

-- Slow on a big table: scans every row
SELECT * FROM orders
WHERE user_id = 42 ORDER BY created_at DESC;

-- Fix: index what you filter and sort by
CREATE INDEX orders_user_created
  ON orders (user_id, created_at DESC);
Spot It
Run EXPLAIN ANALYZE on a slow query. "Seq Scan" on a large table is your sign.
Fix
Index the columns in your WHERE, JOIN and ORDER BY. Don't index everything: each one slows writes a little.
03 · Fetching EverythingDB

Loading the whole table to count, filter or show 20 rows.

The agent pulls every row into your server, then filters or counts it in JavaScript. Or it sends 5,000 rows to the browser and paginates there. The database could have answered in a millisecond.

// Slow: every row crosses the wire, then gets tossed
const all = await db.order.findMany();
const paid = all.filter(o => o.status === "paid").length;

// Fast: let the database do it
const paid = await db.order.count({
  where: { status: "paid" },
});
Spot It
findMany() or SELECT * with no limit, followed by .filter, .length or .reduce.
Fix
Filter, count and sum in the query. Select only the columns you use. Paginate with a LIMIT.
04 · A Connection Per RequestDB

Every request opens a fresh connection to the database.

Opening a connection is slow, and databases only allow so many. On serverless hosts every function can open its own, so a traffic spike runs you out of connections and requests start failing, not just slowing down.

// Slow: a new client on every call
export async function GET() {
  const db = new DbClient();
  ...
}

// Fast: one shared client, created once
const db = globalThis.db ?? (globalThis.db = new DbClient());
Spot It
"Too many connections" errors, or a client created inside a request handler.
Fix
One shared client, and your host's pooled connection string. Supabase calls it the connection pooler.
Serial Vs Parallel

Stop Waiting In Line

Serial means one thing at a time: start the next step when the last one finishes. Parallel means starting everything that doesn't depend on something else at once. AI defaults to serial because it's the easiest code to read. My $3,000 story was this section.

05 · Await In A LoopAsync

50 calls that could run together, made one after another.

Each call waits for the one before it, even though none of them depend on each other. 50 calls at 200ms each is ten seconds. Run them together and it's closer to the slowest one.

// Slow: one at a time
for (const id of ids) results.push(await fetchUser(id));

// Fast: together, but no more than 10 at once
import pLimit from "p-limit";
const limit = pLimit(10);
const results = await Promise.all(
  ids.map(id => limit(() => fetchUser(id)))
);
Spot It
await inside a for loop where each pass doesn't need the last one's result.
Fix
Promise.all with a concurrency cap. Uncapped, 10,000 calls at once will hit rate limits or run out of connections.
06 · WaterfallsAsync

Independent requests stacked on top of each other.

A page needs the user, their plan and their stats. None depend on the others, but the code fetches them in order, so you pay for three round trips. The same thing happens when a component only starts fetching after its parent finishes.

// Slow: three trips back to back
const user  = await getUser();
const plan  = await getPlan();
const stats = await getStats();

// Fast: start all three, wait once
const [user, plan, stats] =
  await Promise.all([getUser(), getPlan(), getStats()]);
Spot It
In the browser's Network tab, requests that form a staircase instead of starting together.
Fix
Start independent work together. Fetch on the server, at the top of the page, not in every child component.
07 · Slow Work In The RequestAsync

The user waits for emails, PDFs and AI calls they don't need yet.

Someone clicks Buy. The code saves the order, sends a receipt, builds an invoice PDF and pings Slack, then says thanks. Only the first step had to happen before the reply. If any of the others hangs, the checkout hangs.

// Slow: the customer waits for all of it
await saveOrder(order);
await sendReceipt(order);
await buildInvoicePdf(order);
return ok();

// Fast: save, queue the rest, answer
await saveOrder(order);
await queue.add("after-order", { orderId: order.id });
return ok();
Spot It
Any request over a second. Look for email, file, AI or third-party calls before the response.
Fix
Do the must-have step, put the rest on a background queue, respond right away.
08 · One Giant Serial JobAsync

A batch job that walks through everything, one piece at a time.

An import, a report or a sync that loops over every day, file or customer in order. It takes hours, one bad record kills the whole run, you can't see how far it got, and more servers don't help because only one is working. That was my 72-hour job.

// Slow: one process, every day in order
for (const day of days) await importSales(day);

// Fast: one job per day, many workers
for (const day of days) await queue.add("import-day", { day });
// workers run several at once, retry failures,
// and progress = jobs done / jobs total
Spot It
A cron job or script with a big loop that takes hours and has to be restarted from the top when it fails.
Fix
Split the work into small jobs on a queue. Run several workers. Retry the failures, not the whole run.
Everywhere Else

Caching, APIs And The Browser

The last four live outside the database: answers you keep recomputing, APIs you call too often, and a browser doing far more work than it should.

09 · No CachingCache

Working out the same answer for every single visitor.

Exchange rates, a product catalog, a dashboard total, the same AI prompt with the same input. If the answer barely changes, computing it fresh on every request is wasted time and, with AI and paid APIs, wasted money.

// Slow: same call, every request
const rates = await getRates();

// Fast: fetch once, reuse for an hour
const rates = await cached("rates", 3600, getRates);
Spot It
The same external call or heavy query in your logs, with the same inputs, over and over.
Fix
Cache it with an expiry. In memory, in Redis, or with your framework's built-in caching.
10 · Chatty APIsNetwork

One call per item, or asking "done yet?" every second.

The agent calls an API once per product when it has a batch endpoint, or polls a job status on a timer when the service would send a webhook. You get slow pages, rate-limit errors and a bigger bill.

// Slow: 200 calls
for (const id of ids) items.push(await api.getProduct(id));

// Fast: 1 call
const items = await api.getProducts({ ids });
Spot It
Rate-limit errors, setInterval around a fetch, or an API call inside a loop.
Fix
Use the batch endpoint. Swap polling for webhooks. Read the API docs before writing the loop.
11 · A Heavy FrontendBrowser

Megabytes of code and images before anything shows up.

A whole date library for one formatted date. An icon pack where you use six icons. A 4 MB photo shown at 300 pixels wide. On a phone over cellular, people leave before it loads.

// Slow: ships the whole library
import _ from "lodash";

// Fast: ships one function
import debounce from "lodash/debounce";
Spot It
Run Lighthouse in Chrome DevTools. Check the size of your JavaScript and your biggest images.
Fix
Import only what you use. Resize and compress images, and lazy-load anything below the fold.
12 · Re-Render LoopsBrowser

The page refetches every time anything changes.

A React effect depends on an object that's rebuilt on every render, so it fires on every render. Or a search box hits the server on every keystroke. The page feels sluggish and your API takes ten times the traffic it should.

// Slow: a new object each render, so this runs each render
const filters = { status: "open" };
useEffect(() => { load(filters); }, [filters]);

// Fast: a stable value
const filters = useMemo(() => ({ status: "open" }), []);
Spot It
The same request firing again and again in the Network tab while you type or click.
Fix
Stable dependencies, debounced inputs, and a data library like TanStack Query or SWR that dedupes requests.
Find It First

Measure Before You Guess

You can't fix slow if you don't know where it is. Five free ways to find out, most of which your agent can run for you.

Tool 01

Count your queries.

Turn on query logging in your ORM or database and load one page. If it runs more than a handful of queries, look for N+1.

Tool 02

Explain the slow ones.

Put EXPLAIN ANALYZE in front of a slow query. It tells you whether the database used an index or read the whole table.

Tool 03

Read the waterfall.

Open the Network tab in Chrome DevTools and reload. A staircase of requests means serial. One giant file means a heavy bundle.

Tool 04

Time each step.

Log a timestamp before and after each step in a slow endpoint or job. The biggest gap is where to start.

Tool 05

Test with real-sized data.

Seed 10,000 rows of fake data and try again. Most of these twelve are invisible with a dozen test rows.

The Prompt

Make Your Agent Find Them

Paste this into Claude Code, Codex or Cursor from the root of your project. It looks for all twelve, ranks them, and waits for you before it changes anything.

Speed.Audit.Prompt
You're a senior engineer doing a performance review of this codebase. It was built fast, mostly with AI, and it's getting slow. Find the bottlenecks before you change anything.

What feels slow: [the page, endpoint or job, or "not sure"]
Stack: [e.g. Next.js, Supabase, Vercel, or work it out from the repo]

Look for these:

Database
1. N+1 queries: a query inside a loop, or one query per item in a list.
2. Missing indexes: columns used in WHERE, JOIN or ORDER BY with no index, foreign keys included.
3. Fetching everything: SELECT * or findMany with no limit, or loading rows just to filter, count or sum them in code.
4. A new database connection per request, or no connection pooling on serverless.

Serial vs parallel
5. await inside a loop over independent items, and the opposite: Promise.all over thousands of items with no concurrency limit.
6. Waterfalls: independent awaits run one after another, or components that only fetch after their parent finishes.
7. Slow work inside a request: email, PDFs, AI calls, image processing or third-party calls the user doesn't need to wait for.
8. Big jobs run as one long serial loop (one day, file or customer at a time) with no queue, no retries and no progress tracking.

Everywhere else
9. No caching for data that rarely changes, including repeated identical AI or API calls.
10. Chatty APIs: one call per item where a batch call exists, or polling where a webhook would do.
11. A heavy frontend: whole-library imports, oversized images, nothing lazy-loaded.
12. Re-render loops: effects or queries that rerun on every render or keystroke.

For each one you find, give me:
- the file and line, with the code quoted
- why it's slow, in one sentence a non-engineer would get
- how bad it is now, and how bad at 10x the data or traffic
- the fix, and what it could break

Rank everything by impact, biggest first. Measure where you can: query logs, EXPLAIN ANALYZE, timing logs, a quick load test. Mark anything you couldn't verify as a suspicion, not a finding.

Don't change any code yet. Give me the ranked list and stop. When I pick one, fix only that one, measure before and after, and show me the numbers.
Pink Means Edit Me

Fill in what feels slow and your stack, or leave them for the agent to work out. Leave the rest alone.

Let It Measure

It finds more when it can run things. Give it a local database with realistic data, or paste in your query logs and a slow request's timings.

One Fix Per PR

Pick the top item, have it fix just that, and check the numbers. Twelve fixes in one PR means you won't know which one broke checkout.

Before You Fix

Four Rules For Faster

Note 01

Fix the biggest one first.

One N+1 on your busiest page is worth more than twenty small cleanups. The ranked list exists so you don't spend a week on the wrong thing.

Note 02

Don't parallelize everything.

Databases have connection limits and APIs have rate limits. Running a thousand things at once just moves the bottleneck. Cap it.

Note 03

No number, no fix.

Ask for a before and after: query count, response time, job duration. If the agent can't show you a number, you don't know it worked.

Note 04

Check the bill too.

Slow code is often expensive code. Servers running for days, paid API calls repeated for every visitor. My fix was about speed and ended up saving about $3,000 a month.

One More Thing

Tools Are The Easy Part.

Anybody can build software now. Not everybody can build a business.

The Solo Founder Lab

Reading about tools is a great way to feel busy. The Lab is for Founders who'd rather get customers: weekly office hours with a CTO who's built two seven-figure software companies, and a room of other Founders who care whether anybody buys what you're making.

Lab.exe✣

Less Theater. More Customers.

Want my 30-Day Launch Plan? It's for Lab members only: validate, plan, build and launch, one week at a time.

See The Solo Founder Lab ▶