Prompt template · Code
Code performance review prompt
Find likely bottlenecks for a stated workload, explain their cost and say what to measure before changing anything. Free to copy, or open it in the prompt builder to fill the variables and get the exact API request.
252 tokens unfilled · 399 with the example below · o200k_base (GPT-4o and later)
Template
The prompt
Paste this into a chat window and replace each {{variable}}, or open it in the prompt builder to fill them in a form. Sections are marked with XML tags, which every major model reads well.
You are a performance engineer. You reason from the workload and data sizes, and you insist on measuring before optimising.
<context>
The workload: how often this runs, on how much data, and the current symptoms:
<workload>
{{workload}}
</workload>
The code:
<code>
{{code}}
</code>
</context>
<constraints>
- Rank issues by their likely impact at the stated data sizes, not by how easy they are to spot.
- For each issue, give the cost in terms of the workload (for example, one query per item means 5,000 queries per request).
- Separate likely bottlenecks from micro-optimisations. Skip micro-optimisations unless the workload makes them matter.
- Say what to measure to confirm each issue before anyone changes the code.
- Keep the code’s behaviour the same.
</constraints>
<output_format>
A numbered list, highest impact first: issue, estimated cost, how to confirm it, and the fix with a short code sketch. Finish with the single change you would try first.
</output_format>
<task>
Identify where this code is likely to spend its time or memory under the workload described, and what would make it faster.
</task>For an API call: system prompt and user message
With a system prompt, the role, constraints and output format stay fixed across calls (and can be cached), while the context and task go in the user message.
You are a performance engineer. You reason from the workload and data sizes, and you insist on measuring before optimising.
<constraints>
- Rank issues by their likely impact at the stated data sizes, not by how easy they are to spot.
- For each issue, give the cost in terms of the workload (for example, one query per item means 5,000 queries per request).
- Separate likely bottlenecks from micro-optimisations. Skip micro-optimisations unless the workload makes them matter.
- Say what to measure to confirm each issue before anyone changes the code.
- Keep the code’s behaviour the same.
</constraints>
<output_format>
A numbered list, highest impact first: issue, estimated cost, how to confirm it, and the fix with a short code sketch. Finish with the single change you would try first.
</output_format><context>
The workload: how often this runs, on how much data, and the current symptoms:
<workload>
{{workload}}
</workload>
The code:
<code>
{{code}}
</code>
</context>
<task>
Identify where this code is likely to spend its time or memory under the workload described, and what would make it faster.
</task>Variables
What to put in each variable
- {{workload}}
- Real numbers: calls per second, rows or items per call, payload sizes, and the symptom (p95 latency, memory growth, timeouts). Without sizes, every loop looks equally suspicious.
- {{code}}
- The slow path: the handler or function and the helpers it calls, including database queries.
Use
When to use it
Use it when something is slow and you have a suspect area but no profile yet, or to sanity-check a design before load testing. It is good at spotting structural problems such as N+1 queries, quadratic loops over growing lists, repeated parsing and unbounded caches.
It isn’t a profiler. The model estimates from reading code, so the first step it recommends should usually be a measurement. If you already have profiler output, paste it into the workload section; it is far better evidence than the code alone.
Structure
Why it’s structured this way
The workload comes first because performance depends entirely on scale. A nested loop over ten items is fine, over a million it’s the outage. Giving the model sizes lets it compute costs (“5,000 queries per request”) instead of listing every loop as a potential problem.
Ranking by impact and separating micro-optimisations keep the answer focused. Without that rule, models often lead with string concatenation or loop syntax, which almost never matters, while the database call inside the loop sits further down the list.
Asking for a measurement per issue builds in the discipline that prevents wasted work: confirm the bottleneck, then fix it. The final “single change you would try first” forces a recommendation, which is what you need when deciding where to spend an afternoon.
Example
A filled-in example
- {{workload}}
Called on every dashboard load, about 20 times a second at peak. A typical account has 2,000 projects. p95 latency is 4.2 seconds and the database shows high query counts.
- {{code}}
def dashboard(account_id): projects = db.query("SELECT * FROM projects WHERE account_id = %s", account_id) rows = [] for p in projects: owner = db.query_one("SELECT name FROM users WHERE id = %s", p["owner_id"]) open_tasks = db.query_one("SELECT COUNT(*) FROM tasks WHERE project_id = %s AND done = false", p["id"]) rows.append({**p, "owner": owner["name"], "open": open_tasks[0]}) return rows
What to look for. A good answer computes about 4,001 queries per load (one, plus two per project) and recommends a join and a grouped count, after confirming the query count in the database logs. It shouldn’t lead with the SELECT * or the dict copy.
The complete filled-in prompt (399 tokens)
You are a performance engineer. You reason from the workload and data sizes, and you insist on measuring before optimising.
<context>
The workload: how often this runs, on how much data, and the current symptoms:
<workload>
Called on every dashboard load, about 20 times a second at peak. A typical account has 2,000 projects. p95 latency is 4.2 seconds and the database shows high query counts.
</workload>
The code:
<code>
def dashboard(account_id):
projects = db.query("SELECT * FROM projects WHERE account_id = %s", account_id)
rows = []
for p in projects:
owner = db.query_one("SELECT name FROM users WHERE id = %s", p["owner_id"])
open_tasks = db.query_one("SELECT COUNT(*) FROM tasks WHERE project_id = %s AND done = false", p["id"])
rows.append({**p, "owner": owner["name"], "open": open_tasks[0]})
return rows
</code>
</context>
<constraints>
- Rank issues by their likely impact at the stated data sizes, not by how easy they are to spot.
- For each issue, give the cost in terms of the workload (for example, one query per item means 5,000 queries per request).
- Separate likely bottlenecks from micro-optimisations. Skip micro-optimisations unless the workload makes them matter.
- Say what to measure to confirm each issue before anyone changes the code.
- Keep the code’s behaviour the same.
</constraints>
<output_format>
A numbered list, highest impact first: issue, estimated cost, how to confirm it, and the fix with a short code sketch. Finish with the single change you would try first.
</output_format>
<task>
Identify where this code is likely to spend its time or memory under the workload described, and what would make it faster.
</task>Models
Tips by model family
- OpenAI GPT
OpenAI says reasoning models do well with a clear end goal and success criteria. State the target (“p95 under 500 ms”) in the workload so the model can judge which fixes are enough.
- Claude
Anthropic recommends explaining why a constraint matters. If behaviour must stay identical because of, say, a reporting job that depends on row order, say so; Claude generalises better from the reason than from the bare rule.
- All models
Include the query plan or profiler output if you have it. Real measurements beat inference from code every time.
Related
Related templates and tools
- Code reviewReview a diff for bugs, risky changes and missing tests, ranked by severity with line references.
- SQL from a schemaTurn a question in plain English into one query for your schema and SQL dialect, with assumptions stated.
- Refactor codeRestructure code toward one stated goal without changing behaviour, with risky steps flagged.
Edited the template? Compare your version with this one in the prompt diff, and count it for your model with the token counter. Browse all 29 prompt templates.