Cursor defaults to brute-force O(n^2) solutions because they are simpler to generate and more common in training data. By adding performance rules to .cursorrules, specifying target complexity in prompts, and asking for complexity analysis, you redirect Cursor toward efficient algorithms using hash maps, sorting, and proper data structures from the start.
Why Cursor generates inefficient logic and how to fix it
AI models optimize for code correctness and readability, not runtime performance. Nested loops, repeated array scans, and string concatenation in loops are the most common inefficiencies in Cursor-generated code. This tutorial teaches you how to get efficient algorithms from the start.
Prerequisites
- Cursor installed with a project open
- Basic understanding of Big-O notation
- Code with performance-sensitive operations
- Familiarity with Cursor Chat (Cmd+L)
Step-by-step guide
Add performance rules to .cursor/rules
Add performance rules to .cursor/rules
Create rules that redirect Cursor away from common inefficient patterns and toward optimal data structures.
1---2description: Performance and algorithmic efficiency rules3globs: "src/**/*.ts"4alwaysApply: true5---67## Performance Rules8- Use Map/Set for lookups instead of Array.find/Array.includes in loops9- Use hash maps for pair/group finding (O(n) not O(n^2))10- Avoid nested loops over the same or related collections11- Use Set for deduplication instead of Array.filter with indexOf12- Concatenate strings with Array.join, not += in loops13- Pre-sort arrays when doing repeated binary searches14- Use early returns/continue to reduce unnecessary iterations15- Cache computed values that are used multiple times1617## Complexity Targets18- Searching: O(log n) or O(1) with hash maps19- Sorting: O(n log n) maximum20- Filtering/mapping: O(n) single pass21- Finding pairs/groups: O(n) with hash maps, not O(n^2) nested loopsExpected result: Cursor avoids common inefficient patterns and uses optimal data structures.
Specify target complexity in prompts
Specify target complexity in prompts
When asking Cursor to generate algorithmic code, include the target time complexity. This immediately redirects it from brute-force to efficient approaches.
1// BAD prompt (produces O(n^2)):2// 'Find duplicate values in this array'34// GOOD prompt (produces O(n)):5// 'Find duplicate values in this array using a Set for6// O(n) time complexity. Do not use nested loops.'78// BAD prompt (produces O(n*m)):9// 'Find common elements between two arrays'1011// GOOD prompt (produces O(n+m)):12// 'Find common elements between two arrays in O(n+m)13// time using a Set for the smaller array.'Pro tip: Always state what to NOT use ('Do not use nested loops') alongside what TO use ('Use a Set'). Cursor responds better to both positive and negative constraints.
Expected result: Cursor generates efficient algorithms matching the specified complexity.
Ask for complexity analysis of generated code
Ask for complexity analysis of generated code
After Cursor generates code, ask it to analyze the time and space complexity. This catches inefficiencies you might miss during code review.
1// Follow-up prompt after receiving generated code:2// What is the time and space complexity of this function?3// If it is worse than O(n log n), suggest an optimization4// using appropriate data structures (Map, Set, sorting).Expected result: Cursor identifies the complexity and suggests optimizations if needed.
Audit existing code for inefficient patterns
Audit existing code for inefficient patterns
Use Cursor to scan your codebase for common performance anti-patterns that may have been generated in earlier sessions without performance rules.
1// Cursor Chat prompt (Cmd+L, Ask mode):2// @codebase Find all instances of these inefficient patterns:3// 1. Array.find() or Array.includes() inside a loop4// 2. Nested for/forEach loops over related collections5// 3. String concatenation with += inside loops6// 4. Array.indexOf() for deduplication7// 5. Repeated .filter().map() chains that could be one pass8// For each finding, show the efficient alternative.Expected result: A list of inefficient patterns with suggested O(n) replacements.
Fix inefficient patterns with Cmd+K
Fix inefficient patterns with Cmd+K
For each inefficiency found, select the code and use Cmd+K to replace it with the optimal version. Reference the performance rules for consistent improvements.
1// BEFORE (O(n^2)):2const duplicates = arr.filter((item, index) =>3 arr.indexOf(item) !== index4);56// Select and press Cmd+K:7// 'Optimize this deduplication to O(n) using a Set.'89// AFTER (O(n)):10const seen = new Set<number>();11const duplicates: number[] = [];12for (const item of arr) {13 if (seen.has(item)) duplicates.push(item);14 else seen.add(item);15}Expected result: O(n^2) pattern replaced with O(n) equivalent using optimal data structures.
Complete working example
1---2description: Algorithmic efficiency and performance rules3globs: "src/**/*.{ts,tsx,js,jsx}"4alwaysApply: true5---67## Common Anti-Patterns and Fixes89### 1. Array.find/includes inside a loop → Use Map/Set10```11// BAD O(n*m):12for (const item of items) {13 if (existingIds.includes(item.id)) { ... }14}1516// GOOD O(n+m):17const idSet = new Set(existingIds);18for (const item of items) {19 if (idSet.has(item.id)) { ... }20}21```2223### 2. Nested loops for pairs → Use Map24```25// BAD O(n^2):26for (let i = 0; i < arr.length; i++)27 for (let j = i+1; j < arr.length; j++)28 if (arr[i] + arr[j] === target) ...2930// GOOD O(n):31const map = new Map();32for (const [i, val] of arr.entries()) {33 if (map.has(target - val)) ...34 map.set(val, i);35}36```3738### 3. String += in loop → Array.join39```40// BAD O(n^2) due to string copying:41let result = '';42for (const s of strings) result += s;4344// GOOD O(n):45const result = strings.join('');46```4748### 4. Repeated filter/map → Single pass49```50// BAD (2 passes):51const active = users.filter(u => u.active);52const names = active.map(u => u.name);5354// GOOD (1 pass):55const names: string[] = [];56for (const u of users) {57 if (u.active) names.push(u.name);58}59```6061## Complexity Targets62- Single collection operations: O(n)63- Two collection operations: O(n + m)64- Searching sorted data: O(log n)65- Sorting: O(n log n) maximumCommon mistakes
Why it's a problem: Cursor using Array.includes() inside a loop for membership checks
How to avoid: Add 'Use Set for membership checks inside loops' to .cursorrules. Cursor will use Set.has() which is O(1).
Why it's a problem: Cursor chaining .filter().map().reduce() when one loop suffices
How to avoid: Add 'Combine filter/map/reduce into single-pass for loops when processing large collections' to your performance rules.
Why it's a problem: Cursor using string concatenation in loops
How to avoid: Add 'Use Array.push then join for string building in loops' to .cursorrules.
Best practices
- Add performance rules to .cursorrules with common anti-patterns and fixes
- Specify target time complexity in every prompt for algorithmic code
- Use Map and Set for O(1) lookups instead of Array.find/includes
- Ask Cursor for complexity analysis after receiving generated code
- Audit existing code periodically with @codebase for inefficient patterns
- Use single-pass loops instead of chained array methods for large datasets
- Pre-compute and cache values used multiple times in hot paths
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Review this function for algorithmic efficiency. Identify the current time and space complexity. If any operations are worse than O(n log n), suggest optimizations using appropriate data structures (Map, Set, sorting). Show the before/after code with complexity annotations.
In Cursor Chat (Cmd+L): @codebase @.cursor/rules/performance.mdc Find all O(n^2) or worse patterns in src/. Focus on: Array.includes in loops, nested loops, string concatenation in loops, and chained array methods. Show the efficient alternative for each finding.
Frequently asked questions
Why does Cursor default to brute-force solutions?
Brute-force is simpler to generate and verify. AI models optimize for correctness first, efficiency second. Explicit complexity targets in your prompt override this default behavior.
Should I always optimize for Big-O?
No. For small datasets (under 100 items), readable code matters more than optimal complexity. Optimize only for hot paths and large datasets. Specify dataset size in your prompt.
Can Cursor optimize existing slow code?
Yes. Select the slow code, press Cmd+K, and prompt: 'Optimize this from O(n^2) to O(n) using a hash map. Keep the same input/output behavior.' Cursor handles these targeted optimizations well.
Does Cursor understand amortized complexity?
Cursor understands basic amortized analysis (like dynamic array resizing) when prompted. For complex amortized analysis, use a thinking model (Claude 3.7 with thinking) and ask for step-by-step reasoning.
How do I measure actual performance improvements?
Ask Cursor to generate a benchmark script: 'Create a benchmark that runs both the O(n^2) and O(n) versions with 100,000 elements and compares execution time.' Run it in your terminal.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation