Claude Code Speed Optimization: Measure Slow Node.js Before Fixing It
A measured Node.js workflow for finding bottlenecks with Claude Code, timers, use cases, pitfalls, and checks.
Your Node.js API has a slow report endpoint, the team wants a fix before the next release, and the first suggestion in chat is “add an index.” That might be right, but it is still a guess until the code tells you where the time goes.
This guide uses Claude Code as the coding assistant, not as an oracle. A bottleneck is the slowest part that controls the whole request. Profiling means measuring runtime so the bottleneck is visible. The safe workflow is to add small timers, run one reproducible command with synthetic data, fix only the largest measured delay, and run the same command again.
The article is about server-side Node.js work: API handlers, batch scripts, CSV exports, and data processing jobs. Browser rendering issues such as layout shift and image loading belong in the separate Core Web Vitals performance guide. SQL query plans also have their own checklist in the SQL optimization guide.
What To Do First
Start with the smallest failing artifact: one endpoint, one script, one fixture, or one CSV export. Do not ask Claude Code to “make the project faster” until there is a command that reproduces the slowness. A focused command keeps the conversation short and makes the final evidence easier to review.
Use terms consistently. An N+1 problem means fetching a list once and then fetching related data once per item. A serial await means independent async calls are forced to wait in order. Memoization means reusing the answer for the same input instead of recomputing it.
A useful first prompt is narrow and approval-aware:
claude -p "src/api/report.ts is slow. Do not rewrite it yet.
Add timing around database fetch, API fetch, transform, and response formatting.
Use synthetic fixture data only. Return the changed files, command to run, and the slowest measured section.
Do not change production settings, billing limits, credentials, or customer-data handling without human approval."
Copy-Paste Measurement Code
The first code should be boring. It should print timings, not redesign the service. Node.js provides performance.now() in the official node:perf_hooks documentation, so no package install is required.
Create measured-report.mjs in a scratch branch or local throwaway folder and run it with Node. The data is synthetic: there are no secrets, tokens, production URLs, or customer rows.
import { performance } from "node:perf_hooks";
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
function createTimer() {
const records = [];
return {
async measure(label, fn) {
const start = performance.now();
const value = await fn();
records.push({ label, ms: Number((performance.now() - start).toFixed(1)) });
return value;
},
report() {
return records.sort((a, b) => b.ms - a.ms);
},
};
}
async function fetchUsers() {
await wait(60);
return Array.from({ length: 6 }, (_, index) => ({ id: index + 1 }));
}
async function fetchOrdersOneByOne(users) {
const orders = [];
for (const user of users) {
await wait(45);
orders.push({ userId: user.id, total: user.id * 10 });
}
return orders;
}
async function fetchOrdersInBatch(users) {
await wait(55);
return users.map((user) => ({ userId: user.id, total: user.id * 10 }));
}
function buildReport(users, orders) {
const ordersByUser = new Map(orders.map((order) => [order.userId, order]));
return users.map((user) => ({ ...user, orderTotal: ordersByUser.get(user.id)?.total ?? 0 }));
}
async function run(fetchOrders) {
const timer = createTimer();
const users = await timer.measure("users", fetchUsers);
const orders = await timer.measure("orders", () => fetchOrders(users));
await timer.measure("report", () => buildReport(users, orders));
console.table(timer.report());
}
console.log("slow version");
await run(fetchOrdersOneByOne);
console.log("batch version");
await run(fetchOrdersInBatch);
Run it with:
node measured-report.mjs
node --prof measured-report.mjs
node --prof-process isolate-*.log > profile.txt
node --prof is a built-in profiler documented in the official Node.js CLI reference. Use it when CPU work remains unclear after simple timers; for many API and batch problems, the small timing table is enough to identify the first target.
Three Real-World Use Cases
Use case 1: Slow API response
Input: an API handler, a route-level test, and one synthetic request payload. Claude Code may add timers around database fetch, external fetch, transformation, and serialization. A human must approve changes that touch production credentials, rate limits, auth, or customer data retention.
Output: a short timing table and one patch aimed at the slowest section. If the slowest section is a query, move to the SQL checklist before adding random indexes. If the slowest section is JSON formatting, keep the fix in application code.
Use case 2: Batch CSV export
Input: a local fixture with fake rows and the command that creates the CSV. Claude Code may measure row loading, joins, formatting, and file writing. A human must approve any move from local fixtures to production exports because real customer data and billing time can be involved.
Output: proof that the export is slow because of N+1 reads, serial API calls, or repeated formatting. The fix is usually batching, limited parallelism, or memoizing formatters, not a rewrite of the whole job.
Use case 3: Pull request review before release
Input: the pull request diff, the existing performance test, and the expected response budget such as “keep p95 under the current service target.” Claude Code may inspect the diff and suggest extra timing. A human must approve the release decision, rollback plan, and any customer-visible SLA claim.
Output: a review note that names the measured risk, the command run, and the sections still unmeasured. This is more useful than a vague “looks faster” comment.
Fix Patterns After Measurement
| Measured symptom | Likely cause | Safer first correction |
|---|---|---|
| Many similar queries or API calls | N+1 fetching | Batch IDs, eager-load relations, or use one API bulk endpoint |
| Independent calls add up in order | Serial await | Use Promise.all for independent work |
| Same transformation repeats | Recalculation | Memoize by input or move stable setup outside the loop |
| Time grows sharply with rows | Nested scan | Build a Map once, or add a database index after checking the query plan |
The table is not a license to skip measurement. It is a way to turn the timing result into the smallest safe patch. When the first fix changes security, production traffic, billing, or customer data, stop and ask for human approval before running it outside the fixture.
Pitfalls And Corrections
Pitfall: asking Claude Code to “optimize this endpoint” with no command. The correction is to require a reproduction command, a fixture, and a timing table before any rewrite.
Pitfall: trusting synthetic numbers as a production benchmark. The correction is to label local data as synthetic and use it only to identify the likely bottleneck. Production conclusions need approved observability data from your own system.
Pitfall: replacing a serial loop with unlimited Promise.all. The correction is to confirm independence first, then use a concurrency limit when the calls hit a database, paid API, or rate-limited service.
Pitfall: adding indexes because the word “database” appears in the slow path. The correction is to inspect the query plan and write down the read/write tradeoff. Indexes can speed reads but add write and storage cost.
Claude Code Scope And Human Approval
Let Claude Code do repeatable engineering chores: add temporary timers, build a synthetic fixture, search for looped queries, propose batching, update a unit test, and summarize the measured before-and-after evidence. Those actions are reversible and easy to review.
Keep human approval for production and business decisions: changing authentication, touching customer records, sending data to external services, raising paid API concurrency, changing billing limits, deploying to production, or claiming a new SLA. The agent can prepare the diff and the checklist; a person owns the risk decision.
A good handoff line is: “Claude may patch local measurement and tests. Human approval is required before using production data, changing secrets, changing billing controls, or deploying.” Put that in the prompt when the repository contains sensitive paths.
Primary CTA
Teams that want this workflow as a shared operating habit can use the localized Claude Code training and consultation page. The useful outcome is not a magic speed claim; it is a repeatable review loop that records command, fixture, measured bottleneck, patch, and remaining risk.
Hands-On Verification
For this refresh I checked the article against the requested quality signals: localized internal links use /en/, the external links point to official Node.js documentation, the code fences are executable JavaScript and shell commands, the example uses only synthetic data, and the CTA points to the English training page.
I did not run a production benchmark, inspect a real customer incident, or claim a measured speedup from a live service. The hands-on check was the article content, syntax shape of the code blocks, link locality, and the separation between what Claude Code may do and what a human must approve.
Related Posts
Claude Code Prompt Library Maintenance for Teams
Version, own, review, deprecate, and measure Claude Code prompts so team workflows become paid assets.
Avoid Dangerous Claude Code Prompts: Stop Auto Pushes, Skipped Tests, and Vague Fixes
Turn risky Claude Code requests into safer prompts with permission boundaries, review steps, and copy-paste checklists.
Claude Code Performance Optimization: From Measurement to Core Web Vitals
Measure and improve LCP, INP, API latency, bundles, and caching with Claude Code and runnable examples.
Free PDF: Claude Code Cheatsheet
Enter your email and download the one-page Claude Code cheatsheet for commands, review habits, and safe workflows.
We handle your data with care and never send spam.
Level up your Claude Code workflow
Start with the free PDF, use Gumroad guides when you need repeatable workflows, and book consultation when rollout or revenue paths need human judgment.
About the Author
Masa
Engineer focused on practical Claude Code workflows. Runs claudecode-lab.com, a 10-language technical media site.
Related Products
Claude Code Quick Reference Cheatsheet
A free one-page reference for daily Claude Code work.
Keep the essential commands, file-reference patterns, CLAUDE.md reminders, prompting habits, review cues, and debugging workflow notes next to your editor.
50 Battle-Tested Claude Code Prompt Templates
Copy, paste, ship. 50 production-ready prompts.
Use proven prompts for code review, refactoring, testing, documentation, debugging, architecture, and incident response.