# Optimize code performance with AI: measure first

URL: https://agentvera.dev/en/blog/optimize-code-performance-with-ai/ · Published: 2026-10-27

Optimize code performance with AI agents: profile first, give the agent real profiles, fix N+1 queries and bundle bloat, and prove each win with a benchmark.

**In short:**

- Never ask an agent to "make it faster" without data. Profile first with Chrome DevTools, Lighthouse, node --cpu-prof, py-spy or cProfile, and give the agent the profile, not your guess.
- Write a benchmark or a repeatable measurement before the change; it is the verification step. A change that does not move the number gets reverted, however clever it looks.
- The usual big wins are boring: N+1 queries, missing indexes, oversized bundles, repeated work that can be cached. Agents find and fix these well when they can see the evidence.
- Keep wins with regression guards: query-count assertions, bundle size budgets and benchmarks in CI, so the next change cannot quietly undo the work.

**To optimize code performance with AI, measure before you prompt: profile the slow path, give the agent the profile, ask for the smallest change that removes the hotspot, and accept it only when a benchmark shows the difference.** Coding agents such as Claude Code, Codex and Gemini CLI are fast at reading a flame graph, tracing a hot function back to its callers and rewriting a query. Left without data, they do what anyone does: guess. And guessed optimizations are the expensive kind, because they make code harder to read without making it faster.

This guide covers a workflow that holds up in practice: define the goal, profile, hand over the evidence, change one thing, verify with a benchmark and lock the win in with a regression guard. Along the way it covers the problems that cause most slowdowns in real apps: N+1 queries, bundle size and missing caches.

## Start with a number, not a feeling

“The dashboard is slow” is not a task. Turn it into something an agent can check:

- **What** is slow: one endpoint, one page load, one CLI command, one batch job.
- **How slow** it is now, measured: p95 latency of an endpoint, time to interactive of a page, run time of a script.
- **What “fast enough” means**: a target, such as “under 300 ms at p95” or “the import finishes in under a minute for 100k rows”.
- **Under which conditions**: data size, cold or warm cache, production build or dev server.

That last point catches a lot of wasted work. A React app on the dev server, a Node service without `NODE_ENV=production`, or a Python job on ten rows of test data will show hotspots that don’t exist in production. Measure the thing you ship.

## Step 1: profile the slow path

Pick the profiler that matches where the time goes.

### In the browser

The **Performance** panel in Chrome DevTools records a trace: long tasks, scripting, layout, network waterfalls. **Lighthouse** gives a lab score with concrete opportunities. The Lighthouse CLI is handy because it writes a file you can hand to an agent:

```bash
npm install -g lighthouse
lighthouse https://localhost:3000/dashboard \
  --only-categories=performance \
  --output=json --output-path=./lighthouse.json
```

If your agent supports MCP, the Chrome DevTools MCP server lets it start a performance trace and read the insights itself:

```json
{
  "mcpServers": {
    "chrome-devtools": {
      "command": "npx",
      "args": ["-y", "chrome-devtools-mcp@latest"]
    }
  }
}
```

### In Node.js

Node has a built-in sampling profiler. `--cpu-prof` writes a `.cpuprofile` file when the process exits, which you can open in the DevTools Performance panel or give to an agent:

```bash
node --cpu-prof --cpu-prof-dir=./profiles server.js
# run the slow request a few times, then stop the server
```

The older `--prof` flag writes a V8 log that `node --prof-process` turns into a text report, which is very easy for an agent to read:

```bash
NODE_ENV=production node --prof server.js
node --prof-process isolate-0x*-v8.log > processed.txt
```

For memory problems, `--heap-prof` writes a `.heapprofile` in the same way.

### In Python

`py-spy` samples a running process without changing your code, which makes it the safe choice for a live service:

```bash
py-spy top --pid 12345                    # live view, like top
py-spy record -o profile.svg --pid 12345  # flame graph
py-spy record -o profile.svg -- python import_job.py
```

For a script you can start yourself, the standard library’s `cProfile` gives exact call counts:

```bash
python -m cProfile -s cumtime import_job.py | head -40
```

As of October 2026, Python 3.15 also ships a `profiling` package with a statistical profiler (`python -m profiling.sampling`) and keeps `cProfile` as an alias of its tracing profiler; on earlier versions, `cProfile` and py-spy are the tools to use.

### In the database

For query time, the database already knows the answer: the slow query log, `pg_stat_statements` on PostgreSQL, and `EXPLAIN ANALYZE` for one query. [Write SQL with AI](/en/blog/write-sql-with-ai/ "Write SQL with AI") covers reading query plans and choosing indexes with an agent, so this guide won’t repeat it.

## Step 2: give the agent the evidence

Now the agent has something real to work with. Hand over the profile and the context, and ask for analysis before code:

```text
The /api/orders endpoint takes about 1.8 s at p95 in production; the target
is 300 ms. Attached: processed.txt from node --prof-process for 50 requests,
and the slow query log for the same period.
Don't change code yet. List the top three hotspots, with the evidence from
the profile for each one (function, self time or total time, call count),
the likely cause in our code (file and line), and a proposed fix. Order
them by expected impact.
```

A few habits make this step work:

- **Give it the raw output, not your summary.** Your summary already contains your guess.
- **Ask for evidence per claim.** “This function is slow” should come with a number from the profile.
- **Keep the agent in the hot path.** Code that takes 2% of the time is not worth a rewrite, however ugly it is.

If the agent says something like “the profile doesn’t show the bottleneck clearly”, believe it, and capture a better profile with more load or the production build. That’s a much better result than a confident guess.

## Step 3: write the benchmark before the fix

The benchmark is your verification step. Write it, run it on the current code, and save the baseline before anything changes.

For a command or script, `hyperfine` runs it many times and reports the mean and spread:

```bash
hyperfine --warmup 3 'node scripts/build-report.js'
```

For a function, use the benchmark support of your stack: `go test -bench=. -benchmem` in Go, `pytest-benchmark` in Python, the bench support in your JavaScript test runner. For an endpoint, a short load test with a fixed number of requests against a production build.

Then tell the agent the rule:

```text
Here's the benchmark and its baseline result. Make one change at a time.
After each change, run the tests and the benchmark three times and report
before/after. If a change doesn't improve the result beyond the noise,
revert it and tell me, even if you think it should help.
```

Two details matter. Compare on the same machine with the same data, because laptops throttle and caches warm up. And keep tests running alongside the benchmark: a faster function that returns the wrong answer is a bug. If the code you’re optimizing has no tests, add them first; [write unit tests with AI](/en/blog/write-unit-tests-with-ai/ "Write unit tests with AI") shows how to get useful ones from an agent.

## Where the time usually goes

In real apps, a small set of problems accounts for most slowdowns. These are the ones to check first.

### N+1 queries

The classic: load a list, then run one extra query per item inside a loop or a template. It looks fine with ten rows in development and falls over with two thousand in production. The fix is to load the related data in one or two queries, with the tool your ORM provides:

| Stack | Eager loading |
| --- | --- |
| Django | `select_related` (joins), `prefetch_related` (separate query) |
| Rails | `includes`, and the Bullet gem to detect N+1 in development |
| SQLAlchemy | `selectinload`, `joinedload` |
| Prisma | `include` |

Agents are good at this fix once they know where it happens. Turn on query logging, open the slow page once, and give the agent the log: a repeated query pattern with different IDs is the fingerprint. Then ask for the fix and for a test that asserts the number of queries on that page, so the problem can’t come back unnoticed.

### Bundle size

For front-end performance, the JavaScript you ship is often the biggest lever. Measure what’s in the bundle first with `source-map-explorer` or `webpack-bundle-analyzer` (or the analyzer for your bundler), then look for the usual causes:

- a large library imported for one function,
- a whole icon set or locale bundle pulled in by one import,
- heavy components loaded on first paint that could be lazy-loaded,
- the same dependency bundled twice in different versions.

Give the agent the analyzer output and ask for changes ranked by bytes saved. Then compare the build output before and after, the same way you compare a benchmark.

### Repeated work and caching

A cache is the right answer when the same expensive result is computed again and again with the same inputs. It is the wrong answer when the computation could just be made cheap, or when nobody has decided what happens when the data changes. Before you accept a cache from an agent, ask it:

```text
For this cache: what's the key, what invalidates it, what's the maximum
staleness we accept, how much memory can it use, and what happens on a
cold start? Show me the measured hit rate or the profile that justifies it.
```

If the answers are vague, the cache will turn into a bug report later. Often the better fix is earlier in the chain: a missing index, a query that fetches every column, a loop that recomputes the same value on each iteration.

### Algorithmic problems

Sometimes the profile shows a single function with a huge call count: a nested loop over two lists, a `.find()` inside a `.map()`, a sort inside a loop. Replacing a linear lookup with a `Map` or `Set` is a classic agent fix, and the benchmark tells you immediately whether it mattered.

## Avoid premature and speculative optimization

Agents love to optimize. Ask one to “improve performance” on a file and it will memoize components, rewrite loops and add caches everywhere. Most of those changes move nothing measurable and make the code harder to change. Rules worth stating plainly in your project instructions:

```markdown
## Performance work
- No optimization without a profile or benchmark that shows the problem.
- One change per commit, with before/after numbers in the message.
- Readability wins over micro-optimizations outside measured hot paths.
- Don't add caches, workers or new dependencies without asking.
```

The same applies to the agent’s own suggestions during unrelated work. If it proposes “while I’m here, I also optimized…”, ask for the numbers or ask it to revert. When something does break after an optimization, [debug code with AI](/en/blog/debug-code-with-ai/ "Debug code with AI") covers how to narrow it down without guessing.

## Step 4: guard the win

Performance degrades quietly, one reasonable change at a time. Turn each fix into a check that fails loudly:

- **Query count tests.** Assert that the orders page runs at most a fixed number of queries. Most frameworks have a helper for this, such as `assertNumQueries` in Django.
- **Bundle budgets.** Tools like `size-limit` fail the build when a bundle grows beyond a set size.
- **Lighthouse in CI.** Run the Lighthouse CLI against a preview build and fail below a score threshold on the pages that matter.
- **Benchmarks against a baseline.** Store the baseline and compare; in Go, `benchstat` compares two benchmark runs and tells you whether the difference is significant.

Agents are good at writing these guards, and it’s worth asking for one in the same task as the fix: “fix the N+1 and add a test that would have caught it”.

## Doing it in AgentVera

AgentVera is a desktop app that runs coding-agent CLIs like Claude Code, Codex and Gemini CLI side by side. Several of its features fit this loop:

- **A browser the agent can drive.** The [agent browser](/en/features/agent-browser/ "Agent browser") is a separate Chrome profile that agents use through Playwright MCP, with DevTools and the console built in, so the agent can open the slow page itself and you can watch it.
- **Send evidence in one shortcut.** [Send to agent](/en/features/send-to-agent/ "Send to agent") (⌘⇧L) sends terminal output, an editor selection, a diff or the browser console to an agent. Profiler output in the terminal goes to the agent without copy and paste; very long output is cut at 12,000 characters, so send the top of the report or save it to a file.
- **Query plans next to the code.** The [database manager](/en/features/database-manager/ "Database manager") (Pro) opens PostgreSQL, MySQL and SQLite with an SQL editor that shows EXPLAIN plans, and agents can query the database through its built-in tool.
- **Benchmarks as acceptance criteria.** Write “the tests pass and the benchmark is at least 30% faster than the baseline” in your message, and [Verify](/en/features/verify/ "Verify") checks it at the end of the turn with a verifier that runs commands but can’t edit files.
- **Undo an optimization that didn’t pay off.** [Checkpoints](/en/features/checkpoints-and-replay/ "Checkpoints and replay") snapshot each turn, so reverting an experiment is one click.
- **Try two approaches at once.** In the [workspace](/en/features/workspace/ "Workspace") grid, run two agents in separate worktrees, say one on caching and one on the query, and keep the one with the better numbers.

## Wrapping up

Optimizing code performance with AI is the same discipline as optimizing without it, just faster: a clear target, a profile, the evidence handed over, one change at a time, a benchmark as proof and a guard to keep the win. The agent does the reading and the rewriting; the numbers decide. If your slowdown came with a dependency upgrade, the workflow in [upgrade dependencies with AI](/en/blog/upgrade-dependencies-with-ai/ "Upgrade dependencies with AI") helps you isolate which package caused it.

To try this workflow on your own project, [download AgentVera](/en/download/ "Download AgentVera").

## Frequently asked questions

**Can an AI agent find performance problems by reading the code?** It can point out likely suspects, such as a query inside a loop, but it cannot know which one matters for your data and traffic. Give it a profile, a slow query log or a trace, and it can focus on the code that actually takes the time.

**Which profiler should I use?** For the browser, the Performance panel in Chrome DevTools and Lighthouse. For Node.js, node --cpu-prof, which writes a .cpuprofile you can open in DevTools. For Python, py-spy for running processes and cProfile for a script you can start yourself.

**How do I know the optimization worked?** Measure the same thing before and after, several runs each, on the same machine. A benchmark tool such as hyperfine for commands, or the benchmark support in your test framework, does the repeated runs for you. If the difference is inside the noise, it did not work.

**Why do agents suggest optimizations that do not help?** Without measurements, a model falls back on general advice: memoize this, use a faster loop, add a cache. Those changes add complexity and often move nothing. Ask for the evidence behind each suggestion and reject anything that is not tied to a measured hotspot.

**How do I stop performance from getting worse again?** Turn each fix into a check: a test that asserts the number of queries on a page, a bundle size budget in CI, or a benchmark compared against a baseline. The check fails before the regression reaches users.

---

**About AgentVera.** AgentVera is a desktop app for macOS, Windows and Linux, built by Solviera Teknoloji. It runs 18 AI coding agents (Claude Code, Codex, Gemini CLI, Copilot, Cursor, Antigravity, opencode, Hermes, Qwen Code, Kimi Code, Kiro, Amp, Droid, Goose, Vibe, Crush, Aider, Cline) side by side, per project, in real terminals with the user's own CLI installs and logins. The free plan has unlimited agents. Download: https://agentvera.dev/en/download/ · Pricing: https://agentvera.dev/en/pricing/
