Development

Performance Optimization

Best practices for writing performant code across frontend, backend, and database layers.

Cursor Add to Cursor
Cursor Rule (.mdc)

Copy this complete rule and save it as a .mdc file in your .cursor/rules directory

# Performance Optimization

## Core Web Vitals

### Largest Contentful Paint (LCP) < 2.5s
- Preload critical resources
- Optimize images (WebP, lazy loading)
- Use CDN for static assets
- Minimize render-blocking resources

### First Input Delay (FID) < 100ms
- Break up long tasks
- Use web workers for heavy computation
- Defer non-critical JavaScript
- Optimize event handlers

### Cumulative Layout Shift (CLS) < 0.1
- Set explicit dimensions on images/videos
- Reserve space for dynamic content
- Avoid inserting content above existing content
- Use transform for animations

## Frontend Optimization

### JavaScript

```typescript
// Lazy load components
const HeavyComponent = lazy(() => import('./HeavyComponent'));

// Debounce expensive operations
const debouncedSearch = debounce(search, 300);

// Memoize expensive calculations
const expensiveValue = useMemo(() => computeExpensive(data), [data]);

// Virtualize long lists
<VirtualizedList items={largeArray} rowHeight={50} />
```

### Images

```html
<!-- Responsive images with srcset -->
<img
  src="image-800.jpg"
  srcset="image-400.jpg 400w, image-800.jpg 800w, image-1200.jpg 1200w"
  sizes="(max-width: 600px) 400px, 800px"
  loading="lazy"
  decoding="async"
  alt="Description"
/>

<!-- Modern formats with fallback -->
<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="Description">
</picture>
```

### CSS

```css
/* Use CSS containment */
.card {
  contain: layout style paint;
}

/* Prefer transform over position changes */
.animated {
  transform: translateX(100px); /* Good */
  /* left: 100px; Bad - triggers layout */
}

/* Use will-change sparingly */
.will-animate {
  will-change: transform;
}
```

### Bundle Optimization

- Enable tree shaking
- Code split by route
- Analyze bundle with webpack-bundle-analyzer
- Use dynamic imports for large dependencies
- Externalize large libraries to CDN

## Backend Optimization

### Database Queries

```sql
-- Add indexes for frequently queried columns
CREATE INDEX idx_users_email ON users(email);

-- Use EXPLAIN to analyze queries
EXPLAIN ANALYZE SELECT * FROM users WHERE email = '[email protected]';

-- Avoid SELECT * in production
SELECT id, name, email FROM users WHERE active = true;

-- Use pagination for large datasets
SELECT * FROM posts ORDER BY created_at DESC LIMIT 20 OFFSET 40;
```

### N+1 Query Prevention

```typescript
// BAD: N+1 queries
const posts = await db.posts.findMany();
for (const post of posts) {
  post.author = await db.users.findUnique({ where: { id: post.authorId } });
}

// GOOD: Single query with join
const posts = await db.posts.findMany({
  include: { author: true }
});
```

### Caching Strategies

```typescript
// In-memory cache with TTL
const cache = new Map();

async function getCachedData(key: string, ttl: number = 60000) {
  const cached = cache.get(key);
  if (cached && Date.now() - cached.timestamp < ttl) {
    return cached.data;
  }

  const data = await fetchData(key);
  cache.set(key, { data, timestamp: Date.now() });
  return data;
}

// Redis caching pattern
async function getUser(id: string) {
  const cached = await redis.get(`user:${id}`);
  if (cached) return JSON.parse(cached);

  const user = await db.users.findUnique({ where: { id } });
  await redis.setex(`user:${id}`, 3600, JSON.stringify(user));
  return user;
}
```

## API Optimization

### Response Compression
```typescript
// Enable gzip/brotli compression
app.use(compression());
```

### Pagination
```typescript
// Cursor-based pagination (better for large datasets)
const posts = await db.posts.findMany({
  take: 20,
  cursor: { id: lastId },
  orderBy: { createdAt: 'desc' }
});
```

### Field Selection
```typescript
// Allow clients to request specific fields
// GET /api/users?fields=id,name,email
const fields = req.query.fields?.split(',') || ['*'];
```

## Monitoring & Profiling

### Key Metrics to Track
- Response time (p50, p95, p99)
- Error rate
- Throughput (requests/second)
- CPU and memory usage
- Database query time

### Tools
- **Frontend**: Lighthouse, Web Vitals, Chrome DevTools
- **Backend**: Node.js profiler, APM tools (DataDog, New Relic)
- **Database**: Query analyzers, slow query logs
Key Capabilities

What this rule helps you achieve

Core Web Vitals optimizationBundle size reductionCaching strategiesDatabase optimization
Tags
performanceoptimizationcachingweb-vitals