Tips & Tricks (Updated: 7/23/2026)

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.

Claude Code Speed Optimization: Measure Slow Node.js Before Fixing It

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 symptomLikely causeSafer first correction
Many similar queries or API callsN+1 fetchingBatch IDs, eager-load relations, or use one API bulk endpoint
Independent calls add up in orderSerial awaitUse Promise.all for independent work
Same transformation repeatsRecalculationMemoize by input or move stable setup outside the loop
Time grows sharply with rowsNested scanBuild 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.

#claude-code #performance #optimization #prompt-engineering #productivity
Free

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.

Masa

About the Author

Masa

Engineer focused on practical Claude Code workflows. Runs claudecode-lab.com, a 10-language technical media site.