Here's what most founders get wrong about performance:
"We'll optimize after we have users."
Let me share uncomfortable truth: You won't get users if you're slow.
Slow page load → 40% bounce rate. Slow API → frustrated developers abandon integration. Slow database → scaling issues before you grow.
Performance isn't optional. It's table stakes.
This guide shows you how to optimize performance for MVPs—without over-engineering or wasting time.
Performance Targets: What's "Fast Enough"?
Before optimizing, know what you're optimizing for.
Web Performance Targets
Metric | Good | Needs Work | Critical |
|---|---|---|---|
First Contentful Paint (FCP) | <1.5s | 1.5-2.5s | >2.5s |
First Input Delay (FID) | <100ms | 100-300ms | >300ms |
Cumulative Layout Shift (CLS) | <0.1 | 0.1-0.25 | >0.25 |
Time to Interactive (TTI) | <3.5s | 3.5-7s | >7s |
API Performance Targets
Metric | Good | Needs Work | Critical |
|---|---|---|---|
P50 Response Time | <100ms | 100-300ms | >300ms |
P99 Response Time | <500ms | 500-1000ms | >1000ms |
Error Rate | <0.1% | 0.1-1% | >1% |
Startup Reality: For MVP, aim for "Good" in first column. "Excellent" is over-engineering at early stage.
Database Performance: Where Wins Come From
Most performance problems start in database.
1. Add Indexes (Biggest Win)
Before (Slow):
sql-- 100,000 users-- Scans all 100,000 rows: 500ms
After (Fast):
sql-- Add indexCREATE INDEX idx_users_email ON users(email);-- Now jumps directly: 5ms
Performance Gain: 100x faster
Rule of Thumb: Index every foreign key and frequently queried column.
2. Use EXPLAIN to Find Slow Queries
sqlEXPLAIN ANALYZE
What to Look For:
- Seq Scan: Scans entire table (bad for large tables)
- Index Scan: Uses index (good)
- High Cost: Query is expensive
If Seq Scan on large table: Add index or improve query.
3. Select Only Needed Columns
Bad (Slow):
sqlSELECT * FROM users WHERE id = 123;-- Returns all 50 columns
Good (Fast):
sqlSELECT id, name, email FROM users WHERE id = 123;-- Returns only 3 columns
Performance Gain: 2-5x faster, less data transfer
4. Use Pagination (Never Select All)
Bad (Memory Exhaustion):
sql-- Tries to load 1,000,000 rowsSELECT * FROM orders;
Good (Efficient):
sql-- Loads only 50 rows at a timeSELECT * FROM orders LIMIT 50 OFFSET 0;
Performance Gain: Prevents OOM errors, queries are always fast
5. Use Connection Pooling
Without Pooling (Slow):
javascript// Creates new connection for every queryconst result = await db.query("SELECT...");connection.close();// 100ms overhead per query
With Pooling (Fast):
javascriptconst pool = new Pool({ max: 10, idleTimeoutMillis: 30000 });const result = await pool.query("SELECT...");// Connection reused, no overhead
Performance Gain: 2-3x faster, less database load
API Performance: Speed Without Overhead
1. Compress Responses
Without Compression:
javascript// 1MB JSON responsereturn res.json({ data: largeObject });
With Compression:
javascriptimport compression from "compression";app.use(compression()); // Automatic gzip// Now transfers ~100KBreturn res.json({ data: largeObject });
Performance Gain: 10x less data transfer, faster downloads
2. Use HTTP/2
HTTP/2 multiplexes requests over single connection.
Implementation:
- Vercel/Netlify: Automatic HTTP/2
- Nginx: Add
http2 on;directive - Node.js: Use spdy or built-in HTTP/2 (Node 15+)
Performance Gain: 20-50% faster for multiple concurrent requests
3. Cache Frequently Accessed Data
In-Memory Caching (Redis):
javascript// Without cache: Every request hits databaseconst user = await db.query("SELECT * FROM users WHERE id = ?", [id]);// With cache: First request hits DB, others from memorylet user = await redis.get(`user:${id}`);if (!user) {user = await db.query("SELECT * FROM users WHERE id = ?", [id]);await redis.set(`user:${id}`, JSON.stringify(user), "EX", 3600);}
Performance Gain: 50-100x faster for cached data
4. Use CDN for Static Assets
Serve static files from edge, not your servers.
Setup:
javascript// Express exampleapp.use(express.static("public", {maxAge: "1y", // Cache for 1 yearetag: true, // Enable ETag}));
CDN Options:
- Cloudflare: Free, easy setup
- Vercel: Automatic CDN for deployments
- AWS CloudFront: Paid but powerful
Performance Gain: 50-80% faster static asset loading
Frontend Performance: First Impressions Matter
1. Optimize Images (Huge Win)
Problem: Images are often 50-80% of page weight.
Solutions:
Compress Images:
bash# Use modern formatsffmpeg -i input.png -output.webp # 30-50% smallerffmpeg -i input.jpg -output.avif # 50-70% smaller
Lazy Loading:
html<imgsrc="placeholder.jpg"data-src="actual-image.jpg"loading="lazy"alt="Description"/>
Responsive Images:
html<picture><source srcset="image-small.webp" media="(max-width: 600px)" /><source srcset="image-medium.webp" media="(max-width: 1200px)" /><img src="image-large.jpg" alt="Description" /></picture>
Performance Gain: 30-70% faster page loads
2. Minify and Bundle CSS/JS
Build Time Optimization:
javascript// Vite (automatic minification)export default defineConfig({build: {minify: "terser",rollupOptions: {output: {manualChunks: {vendor: ["react", "react-dom"],},},},},});
Performance Gain: 30-50% smaller bundles, faster downloads
3. Use Code Splitting
Split code so users only load what they need.
javascript// Lazy load routesconst Dashboard = lazy(() => import("./Dashboard"));const Settings = lazy(() => import("./Settings"));// Load on demand<Suspense fallback={<Loading />}><Routes><Route path="/dashboard" element={<Dashboard />} /><Route path="/settings" element={<Settings />} /></Routes></Suspense>;
Performance Gain: 40-60% faster initial page loads
4. Optimize Fonts
Problem: Web fonts block rendering while loading.
Solutions:
Font Display Strategy:
css@font-face {font-family: "CustomFont";src: url("/font.woff2") format("woff2");font-display: swap; /* Shows fallback immediately */}
Preload Critical Fonts:
html<link rel="preload" href="/font.woff2" as="font" crossorigin="anonymous" />
Performance Gain: Eliminates FOIT (Flash of Invisible Text)
5. Reduce Third-Party Scripts
Every third-party script adds delay.
Audit Scripts:
html<!-- Remove or defer these if not critical --><script src="https://cdn.tracking.com/analytics.js"></script><script src="https://cdn.chat.com/widget.js"></script>
Strategies:
- Remove: Unused scripts (old tracking, deprecated widgets)
- Defer: Load after critical content
- Lazy Load: Load only when needed (chat widgets, modals)
Performance Gain: 100-500ms faster initial render
Caching Strategy: Cache Smart, Not Everything
Caching Levels
1. Browser Caching (Free)
javascript// Cache headers for static assetsapp.use(express.static("public", {maxAge: "1y", // Cache for 1 yearetag: true, // Revalidate only if changed}));
2. Application Caching (Redis/Memcached)
javascript// Cache expensive operationsconst getExpensiveData = async (key) => {let data = await redis.get(key);if (!data) {data = await expensiveOperation();await redis.set(key, JSON.stringify(data), "EX", 3600); // 1 hour}return JSON.parse(data);};
3. CDN Caching (Cloudflare/Vercel)
javascript// Cache API responsesapp.get("/api/data", async (req, res) => {const data = await getData();res.set("Cache-Control", "public, max-age=300"); // 5 minutesres.json(data);});
What to Cache vs What Not:
Cache | Don't Cache |
|---|---|
Static assets (CSS, JS, images) | User-specific data |
Expensive computations | Authenticated data |
Search results (short-lived) | Payment transactions |
Static assets (CSS, JS, images) | User-specific data |
|---|---|
Expensive computations | Authenticated data |
Search results (short-lived) | Payment transactions |
Performance Monitoring: Measure to Improve
You can't optimize what you don't measure.
Essential Monitoring Tools
Web Vitals:
javascript// Automatic Web Vitals measurementimport { onCLS, onFID, onFCP, onLCP, onTTFB } from "web-vitals";onLCP((metric) => console.log(metric));onFID((metric) => console.log(metric));onCLS((metric) => console.log(metric));
APM Tools:
- Sentry: Error tracking + performance
- Datadog: Full-stack monitoring
- New Relic: APM and infrastructure
- Google Lighthouse CI: Automated performance tests
What to Track
Core Web Vitals:
- First Contentful Paint (FCP)
- Largest Contentful Paint (LCP)
- First Input Delay (FID)
- Cumulative Layout Shift (CLS)
- Time to Interactive (TTI)
API Metrics:
- Response time (p50, p95, p99)
- Error rate by endpoint
- Request throughput
- Database query times
Performance Optimization Checklist
Use this before launching MVP.
Database
- Indexes on foreign keys and frequent queries
- Slow queries identified with EXPLAIN
- Pagination implemented (no SELECT *)
- Connection pooling configured
- N+1 queries addressed
- Caching strategy defined
API
- Response compression enabled (gzip/brotli)
- HTTP/2 enabled
- Cache headers configured
- Expensive operations cached
- Rate limiting prevents abuse
- Error responses don't leak info
Frontend
- Images optimized (compressed, lazy loaded, responsive)
- CSS/JS minified and bundled
- Code splitting implemented
- Fonts optimized (preload, font-display)
- Third-party scripts minimized
- Critical CSS inlined
Infrastructure
- CDN configured for static assets
- HTTP/2 enabled
- SSL/TLS configured
- Gzip/brotli compression enabled
- Monitoring and alerting configured
Common Performance Mistakes
1. Premature Optimization
Mistake: "Let's optimize everything before launching"
Reality: You optimize things that don't matter, miss actual bottlenecks.
Fix: Measure first, then optimize. Focus on p95/p99, not averages.
2. Over-Caching
Mistake: "Cache everything for speed"
Reality: Stale data causes bugs. Cache invalidation is complex.
Fix: Cache carefully. Understand cache invalidation costs.
3. Ignoring Mobile Performance
Mistake: Optimizing only desktop
Reality: 50%+ of traffic is mobile. Mobile CPUs are slower.
Fix: Test and optimize for mobile. Use lightweight solutions.
4. Not Monitoring Production
Mistake: "Performance is good in dev"
Reality: Production is always slower. Users have slower networks.
Fix: Monitor real user performance in production.
5. Micro-Optimizations
Mistake: Saving 10ms in 10 different places
Reality: Total impact is 100ms, but complexity increased 10x.
Fix: Focus on biggest wins first. Low-hanging fruit > micro-optimizations.
Related Reading
If you found this helpful, you might also enjoy:
- Why Startups Build Wrong Architecture - Architecture decisions
- Database Design Mistakes Startups Make - Database optimization
- API Design Best Practices - API performance
- How to Evaluate Codebase - Performance review
Need Help Optimizing Your MVP?
At Startupbricks, we've helped dozens of startups optimize performance from slow to fast. We know what bottlenecks to look for, what optimizations provide biggest wins, and how to implement without over-engineering.
Whether you need:
- Performance audit and recommendations
- Database optimization
- API performance improvements
- Frontend optimization
Let's talk about making your MVP fast.
Ready to optimize? Download our free Performance Checklist and start today.
