📊 PART 1: PERFORMANCE OPTIMIZATION
🎯 Use This Framework: "CRISP-LOAD" (Easy to Remember)
- C - Code Optimization
- R - Rendering Optimization
- I - Image/Asset Optimization
- S - State Management
- P - Progressive Enhancement
- L - Lazy Loading
- O - Output Caching
- A - API Optimization
- D - Database Optimization
🎨 FRONTEND PERFORMANCE (React Focus)
1. Code Optimization (C)
Answer to interviewer:
"After 13 years, I've found code optimization starts at the component level. Here's my approach:"
❌ BAD: Re-renders on every parent update
const UserCard = ({ user }) => {
return <div>{user.name}</div>;
};
✅ GOOD: Memoized component
const UserCard = React.memo(({ user }) => {
return <div>{user.name}</div>;
}, (prevProps, nextProps) => {
return prevProps.user.id === nextProps.user.id;
});
✅ BETTER: useMemo for expensive calculations
const Dashboard = ({ data }) => {
const sortedData = useMemo(() => {
return data.sort((a, b) => b.value - a.value);
}, [data]);
return <Chart data={sortedData} />;
};
✅ BEST: useCallback for function props
const ParentComponent = () => {
const handleClick = useCallback((id) => {
updateUser(id);
}, []); // Dependencies array
return <ChildComponent onClick={handleClick} />;
};
Key Points to Mention:
- React.memo for pure components (prevents re-renders)
- useMemo for expensive computations (10ms+ calculations)
- useCallback for function props passed to children
- Code splitting with React.lazy() and Suspense
- Tree shaking (remove unused code)
- Bundle analysis with webpack-bundle-analyzer
Impressive metric to mention:
"In my last project, implementing React.memo reduced re-renders by
60%, dropping Time to Interactive from 4.2s to 1.8s."
2. Rendering Optimization (R)
Answer to interviewer:
"React 18 concurrent features changed how I optimize rendering. Here's my strategy:"
✅ Virtual Scrolling for large lists
import { FixedSizeList } from 'react-window';
const LargeList = ({ items }) => (
<FixedSizeList
height={600}
itemCount={items.length}
itemSize={50}
width="100%"
>
{({ index, style }) => (
<div style={style}>{items[index].name}</div>
)}
</FixedSizeList>
);
✅ Debouncing expensive operations
import React, { useState, useDeferredValue } from "react";
const bigList = Array.from({ length: 10000 }, (_, i) => `Item ${i}`);
export default function SearchExample() {
const [query, setQuery] = useState("");
// 👇 Defer the expensive value
const deferredQuery = useDeferredValue(query);
const filteredList = bigList.filter(item =>
item.toLowerCase().includes(deferredQuery.toLowerCase())
);
return (
<div>
<input
type="text"
placeholder="Search..."
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<ul>
{filteredList.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}
Answer to interviewer:
“I use useDeferredValue to prioritize urgent updates like user input and defer non-urgent updates like rendering large filtered lists.”
✅ startTransition for non-urgent updates
import { useState, useTransition } from 'react';
function SearchComponent({ list }) {
const [input, setInput] = useState('');
const [filtered, setFiltered] = useState(list);
const [isPending, startTransition] = useTransition();
const handleChange = (e) => {
const value = e.target.value;
setInput(value); // urgent update
startTransition(() => {
const result = list.filter(item =>
item.toLowerCase().includes(value.toLowerCase())
);
setFiltered(result); // non-urgent update
});
};
return (
<div>
<input value={input} onChange={handleChange} />
{isPending && <p>Loading...</p>}
<ul>
{filtered.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}
Answer to interviewer:
💡 What’s Happening Here • setInput → urgent (user typing should never lag) • setFiltered → non-urgent (heavy work, can wait) • startTransition → tells React: “This can be interrupted if user types again” “If I already have a value and want React to delay its effect, I use useDeferredValue. But if I want to explicitly mark some updates as low priority and also show a pending UI state, I use useTransition.”
Key Points to Mention:
- Virtual scrolling (react-window) for 1000+ items
- Pagination/infinite scroll vs loading all data
- useDeferredValue for input-heavy UI
- startTransition for non-blocking updates
- Web Workers for heavy computations
- RequestIdleCallback for low-priority tasks
Impressive metric:
"Implemented virtual scrolling for a 10,000-row table, reduced
initial render from 8s to 200ms."
3. Image/Asset Optimization (I)
Answer to interviewer:
"Images typically account for 50% of page weight. My optimization stack:"
✅ Next.js Image component (automatic optimization)
import Image from 'next/image';
<Image
src="/profile.jpg"
width={400}
height={400}
alt="Profile"
loading="lazy"
placeholder="blur"
quality={85}
/>
✅ Responsive images with srcset
<img
src="hero-800.webp"
srcset="
hero-400.webp 400w,
hero-800.webp 800w,
hero-1200.webp 1200w
"
sizes="(max-width: 600px) 400px, 800px"
alt="Hero"
/>
Images Optimization
- WebP/AVIF format (30% smaller than JPEG)
- Lazy loading (loading="lazy")
- CDN with image optimization
- Responsive images (srcset)
- Compress images
- Remove EXIF data
Assets Optimization
- SVG for icons (vs icon fonts)
- Inline critical SVGs
- Minify CSS/JS
- Remove unused CSS (PurgeCSS)
- Tree-shake libraries
Impressive metric:
"Converted images to WebP + lazy loading reduced LCP from 3.8s to
1.2s, moved from 'Needs Improvement' to 'Good' in Core Web Vitals."
4. State Management (S)
Answer to interviewer:
"Poor state management is the #1 cause of React performance issues. Here's how I handle it:"
❌ BAD: Global state causing unnecessary re-renders
const App = () => {
const [appState, setAppState] = useState({
user: {},
cart: [],
notifications: []
});
// Every update re-renders entire app!
};
✅ GOOD: Separate contexts
const UserContext = createContext();
const CartContext = createContext();
const NotificationsContext = createContext();
✅ BETTER: Zustand for granular updates
import create from 'zustand';
const useStore = create((set) => ({
user: null,
cart: [],
updateCart: (items) => set({ cart: items })
}));
// Only components using cart re-render
const Cart = () => {
const cart = useStore(state => state.cart);
// ...
};
State Management Options:
- Context API: Split by domain (don't use one giant context)
- Zustand: Simple, fast, no providers needed
- Jotai: Atomic, bottom-up state
- Redux Toolkit: For complex apps (with RTK Query)
- React Query: Server state management (caching, refetching)
- LocalStorage: Persist cart, theme, preferences
Impressive statement:
"Migrated from Context API to Zustand, reduced re-renders by 70%.
Combined with React Query for server state, eliminated 90% of
loading spinners through smart caching."
5. Progressive Enhancement (P)
Answer to interviewer:
"Modern web should work for everyone. My progressive enhancement strategy:"
✅ SSR/SSG for initial load
// Next.js example
export async function getStaticProps() {
const data = await fetchData();
return { props: { data } };
}
✅ Hydration optimization
import dynamic from 'next/dynamic';
const HeavyComponent = dynamic(
() => import('./HeavyComponent'),
{ ssr: false } // Skip SSR for client-only components
);
✅ Prefetch critical resources
<link rel="preload" href="/font.woff2" as="font" crossorigin />
<link rel="prefetch" href="/next-page.js" />
<link rel="preconnect" href="https://api.example.com" />
Progressive Enhancement Stack:
- SSR/SSG: Next.js, Remix, Astro
- Streaming SSR: React 18 Suspense
- Critical CSS: Inline above-the-fold styles
- Font optimization: font-display: swap
- Service Workers: Workbox for caching
- HTTP/2 Server Push: Critical resources
- Resource hints: preload, prefetch, preconnect
Impressive metric:
"Implemented SSR + service worker strategy. Time to First Byte
dropped from 800ms to 120ms. Offline mode increased engagement by
23%."
6. Lazy Loading (L)
Answer to interviewer:
"Lazy loading is essential for modern SPAs. My implementation:"
✅ Component lazy loading
const Profile = lazy(() => import('./Profile'));
const Dashboard = lazy(() => import('./Dashboard'));
<Suspense fallback={<Spinner />}>
<Routes>
<Route path="/profile" element={<Profile />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</Suspense>
✅ Image lazy loading
const LazyImage = ({ src, alt }) => {
const [imageSrc, setImageSrc] = useState(placeholder);
const imgRef = useRef();
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
setImageSrc(src);
observer.disconnect();
}
});
observer.observe(imgRef.current);
return () => observer.disconnect();
}, [src]);
return <img ref={imgRef} src={imageSrc} alt={alt} />;
};
Lazy Loading Strategy:
- Route-based code splitting (automatic with Next.js)
- Component lazy loading (React.lazy)
- Library lazy loading (import() for heavy libs)
- Image lazy loading (IntersectionObserver)
- Below-the-fold content lazy loading
- Defer non-critical JS (defer/async attributes)
⚙️ BACKEND PERFORMANCE (Node.js Focus)
7. Output Caching (O)
Answer to interviewer:
"Caching is the biggest performance multiplier on the backend. My caching strategy:"
✅ Redis for application cache
import Redis from 'ioredis';
const redis = new Redis();
app.get('/api/user/:id', async (req, res) => {
const cacheKey = `user:${req.params.id}`;
// Try cache first
const cached = await redis.get(cacheKey);
if (cached) {
return res.json(JSON.parse(cached));
}
// Cache miss: fetch from DB
const user = await User.findById(req.params.id);
// Cache for 5 minutes
await redis.setex(cacheKey, 300, JSON.stringify(user));
res.json(user);
});
✅ Cache invalidation
app.put('/api/user/:id', async (req, res) => {
const user = await User.findByIdAndUpdate(req.params.id, req.body);
// Invalidate cache
await redis.del(`user:${req.params.id}`);
res.json(user);
});
✅ HTTP caching headers
app.get('/api/posts', (req, res) => {
res.set({
'Cache-Control': 'public, max-age=300', // 5 minutes
'ETag': generateETag(posts),
'Last-Modified': posts.updatedAt
});
res.json(posts);
});
Caching Layers:
- Layer 1: Browser Cache (Cache-Control headers)
- Layer 2: CDN Cache (CloudFront, Cloudflare)
- Layer 3: Application Cache (Redis, Memcached)
- Layer 4: Database Query Cache
- Layer 5: Database Connection Pool
Cache Strategy:
- Static assets: 1 year cache
- API responses: 5-60 minutes cache
- User-specific data: No cache or private cache
- Public data: Aggressive caching
Impressive metric:
"Implemented 3-tier caching (CDN + Redis + query cache). API
response time dropped from 450ms to 12ms for cached data. Cache hit
rate: 87%. Server load reduced by 65%."
8. API Optimization (A)
Answer to interviewer:
"API design directly impacts frontend performance. My optimization approach:"
✅ Pagination (don't load all data)
app.get('/api/posts', async (req, res) => {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 20;
const skip = (page - 1) * limit;
const posts = await Post.find()
.skip(skip)
.limit(limit)
.lean(); // MongoDB: skip Mongoose overhead
res.json({
data: posts,
page,
totalPages: Math.ceil(totalCount / limit)
});
});
✅ Field filtering (don't send unnecessary data)
app.get('/api/users', async (req, res) => {
const fields = req.query.fields?.split(',').join(' ') || '';
const users = await User.find()
.select(fields || 'name email avatar')
.lean();
res.json(users);
});
✅ Compression
import compression from 'compression';
app.use(compression()); // gzip responses
API Optimization Checklist:
- Pagination: Limit 20-50 items per page
- Field filtering: Let client specify fields
- Batch endpoints: Combine multiple requests
- GraphQL: For complex data requirements
- Response compression: gzip/brotli
- HTTP/2: Multiplexing
- Connection pooling: Reuse DB connections
- Async/await: Non-blocking operations
- Streaming: For large responses
- Rate limiting: Prevent abuse
Impressive metric:
"Implemented GraphQL + field filtering. Average API response size
dropped from 150KB to 18KB (88% reduction). Combined with
pagination, initial page load improved from 2.8s to 0.9s."
9. Database Optimization (D)
Answer to interviewer:
"Database is often the bottleneck. My optimization strategy:"
✅ Indexing (most critical)
// MongoDB
db.users.createIndex({ email: 1 }, { unique: true });
db.posts.createIndex({ userId: 1, createdAt: -1 });
db.posts.createIndex({ tags: 1 }); // Array field index
// PostgreSQL
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_posts_user_date ON posts(user_id, created_at DESC);
CREATE INDEX idx_posts_tags ON posts USING GIN(tags); // JSON index
✅ Query optimization - Avoid N+1 problem
// BAD: N+1 query problem
const users = await User.find();
for (let user of users) {
user.posts = await Post.find({ userId: user.id }); // N queries!
}
// GOOD: Use joins/populate
const users = await User.find().populate('posts'); // 1 query
✅ Select only needed fields
// BAD
const users = await User.find(); // Gets all fields
// GOOD
const users = await User.find().select('name email avatar');
SQL Optimization
- Indexes on frequently queried columns
- Composite indexes for multi-column queries
- EXPLAIN ANALYZE to identify slow queries
- Avoid SELECT *, specify columns
- Use JOINs instead of multiple queries
- Connection pooling (pg-pool)
- Read replicas for scaling reads
- Materialized views for complex aggregations
NoSQL (MongoDB) Optimization
- Compound indexes for common queries
- Projection (select specific fields)
- .lean() to skip Mongoose overhead
- Aggregation pipeline for complex queries
- Sharding for horizontal scaling
- Read preference: secondary for reads
Impressive metric:
"Added indexes on user_id and created_at. Query time dropped from
2.3s to 48ms (98% improvement). Implemented read replicas, scaled
read throughput from 1K to 10K queries/second."
🌐 NETWORK OPTIMIZATION
Answer to interviewer:
"Network is often overlooked but critical. My optimization approach:"
✅ Resource hints
<link rel="preconnect" href="https://api.example.com" />
<link rel="dns-prefetch" href="https://fonts.googleapis.com" />
<link rel="preload" href="/critical.css" as="style" />
<link rel="prefetch" href="/next-page.js" />
✅ Service Worker for offline
// sw.js
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
});
✅ WebSocket for real-time (vs polling)
const ws = new WebSocket('wss://api.example.com');
ws.onmessage = (event) => {
updateUI(JSON.parse(event.data));
};
Network Optimization Checklist:
- CDN: CloudFront, Cloudflare (edge caching)
- HTTP/2: Enabled by default with HTTPS
- HTTP/3 (QUIC): Faster than TCP
- Compression: gzip (older) or brotli (better)
- Minification: JS, CSS, HTML
- Resource hints: preconnect, prefetch, preload
- Service Workers: Offline-first strategy
- WebSocket: For real-time (not polling)
- Keep-Alive: Reuse TCP connections
- Reduce redirects: Each adds latency
📏 PERFORMANCE METRICS TO MENTION
Core Web Vitals (Google's standards)
LCP (Largest Contentful Paint)
- Target: < 2.5 seconds
- Measures: Loading performance
- Fix: Optimize images, use CDN, lazy load
FID (First Input Delay)
- Target: < 100 milliseconds
- Measures: Interactivity
- Fix: Minimize JS, code splitting
CLS (Cumulative Layout Shift)
- Target: < 0.1
- Measures: Visual stability
- Fix: Set image dimensions, avoid dynamic content
Tools to mention:
- Lighthouse (Chrome DevTools)
- WebPageTest (detailed analysis)
- Chrome DevTools Performance tab
- React DevTools Profiler
- webpack-bundle-analyzer
- New Relic / Datadog (production monitoring)
Impressive statement:
"In my last project, we achieved all 'Good' Core Web Vitals scores: LCP 1.8s, FID 45ms, CLS 0.05. This moved us from page 3 to page 1 in Google search results, increasing organic traffic by 145%."
"In my last project, we achieved all 'Good' Core Web Vitals scores: LCP 1.8s, FID 45ms, CLS 0.05. This moved us from page 3 to page 1 in Google search results, increasing organic traffic by 145%."
🔒 PART 2: WEBSITE SECURITY
🎯 Use This Framework: "SAFE-COAST" (Easy to Remember)
- S - SQL Injection Protection
- A - Authentication & Authorization
- F - Frontend Security (XSS, CSRF)
- E - Encryption (HTTPS, Data)
- C - CORS Configuration
- O - Output Encoding
- A - API Security
- S - Security Headers
- T - Third-party Dependencies
🛡️ FRONTEND SECURITY
1. XSS (Cross-Site Scripting) Prevention
Answer to interviewer:
"XSS is the #1 frontend security risk. Here's how I prevent it:"
❌ VULNERABLE: Direct HTML injection
const UserComment = ({ comment }) => {
return <div dangerouslySetInnerHTML={{ __html: comment }} />;
};
// Attacker comment: "<script>alert('XSS')</script>"
✅ SAFE: React escapes by default
const UserComment = ({ comment }) => {
return <div>{comment}</div>; // Automatically escaped
};
✅ SAFE: Sanitize if HTML needed
import DOMPurify from 'dompurify';
const UserComment = ({ comment }) => {
const sanitized = DOMPurify.sanitize(comment);
return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;
};
✅ Content Security Policy (CSP)
<meta
http-equiv="Content-Security-Policy"
content="
default-src 'self';
script-src 'self' 'unsafe-inline' https://cdn.example.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
"
/>
XSS Prevention Checklist:
- Never use dangerouslySetInnerHTML (unless sanitized)
- Sanitize user input (DOMPurify, sanitize-html)
- Content Security Policy (CSP) headers
- HTTPOnly cookies (JS can't access)
- Validate input on client AND server
- Escape output in templates
- Use textContent instead of innerHTML
2. CSRF (Cross-Site Request Forgery) Prevention
Answer to interviewer:
"CSRF tricks users into executing unwanted actions. My prevention:"
✅ CSRF Token (Backend generates, frontend sends)
// Backend (Express)
import csrf from 'csurf';
app.use(csrf({ cookie: true }));
app.get('/form', (req, res) => {
res.json({ csrfToken: req.csrfToken() });
});
// Frontend
const deleteAccount = async () => {
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;
await fetch('/api/account', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
}
});
};
✅ SameSite Cookies
res.cookie('session', token, {
httpOnly: true,
secure: true,
sameSite: 'strict' // or 'lax'
});
CSRF Prevention Checklist:
- CSRF tokens for state-changing operations
- SameSite cookies (Strict or Lax)
- Verify Origin/Referer headers
- Use POST for state changes (not GET)
- Double-submit cookies pattern
- Custom headers (AJAX requests)
🔐 BACKEND SECURITY
3. SQL Injection Prevention
Answer to interviewer:
"SQL injection can expose entire database. Here's my protection:"
❌ VULNERABLE: String concatenation
app.get('/user', async (req, res) => {
const { email } = req.query;
const query = `SELECT * FROM users WHERE email = '${email}'`;
const users = await db.query(query);
// Attacker: email = "' OR '1'='1"
// Returns ALL users!
});
✅ SAFE: Parameterized queries (PostgreSQL)
app.get('/user', async (req, res) => {
const { email } = req.query;
const query = 'SELECT * FROM users WHERE email = $1';
const users = await db.query(query, [email]);
});
✅ SAFE: ORM (Mongoose, Sequelize, Prisma)
app.get('/user', async (req, res) => {
const { email } = req.query;
const user = await User.findOne({ email }); // Mongoose
});
✅ Input validation
import { body, validationResult } from 'express-validator';
app.post('/user',
body('email').isEmail().normalizeEmail(),
body('age').isInt({ min: 1, max: 120 }),
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Safe to process
}
);
SQL Injection Prevention:
- Always use parameterized queries
- Use ORM (Mongoose, Sequelize, Prisma)
- Never concatenate user input into queries
- Validate and sanitize input
- Principle of least privilege (DB user permissions)
- Escape special characters
- Input validation library (express-validator, joi)
4. Authentication & Authorization
Answer to interviewer:
"Proper auth is critical. My implementation:"
✅ JWT with refresh tokens
import jwt from 'jsonwebtoken';
// Login
app.post('/login', async (req, res) => {
const { email, password } = req.body;
// Verify user
const user = await User.findOne({ email });
const isValid = await bcrypt.compare(password, user.password);
if (!isValid) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Generate tokens
const accessToken = jwt.sign(
{ userId: user.id },
process.env.JWT_SECRET,
{ expiresIn: '15m' }
);
const refreshToken = jwt.sign(
{ userId: user.id },
process.env.REFRESH_SECRET,
{ expiresIn: '7d' }
);
res.json({ accessToken, refreshToken });
});
✅ Authentication middleware
const authenticateToken = (req, res, next) => {
const token = req.headers['authorization']?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token' });
}
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) {
return res.status(403).json({ error: 'Invalid token' });
}
req.user = user;
next();
});
};
✅ Password hashing
import bcrypt from 'bcrypt';
const hashPassword = async (password) => {
const salt = await bcrypt.genSalt(10);
return bcrypt.hash(password, salt);
};
✅ Rate limiting (prevent brute force)
import rateLimit from 'express-rate-limit';
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // 5 attempts
message: 'Too many login attempts, try again later'
});
app.post('/login', loginLimiter, async (req, res) => {
// Login logic
});
Authentication Security Checklist:
- Bcrypt for password hashing (cost factor 10+)
- JWT with short expiration (15 min access token)
- Refresh tokens (7 days, stored in DB)
- HTTPOnly cookies for tokens
- Rate limiting on login endpoint
- Account lockout after N failed attempts
- Password requirements (length, complexity)
- 2FA/MFA (TOTP, SMS)
- Session management (logout all devices)
- Password reset with token expiration
5. Encryption
Answer to interviewer:
"Data encryption at rest and in transit. My approach:"
✅ Encrypt sensitive data at rest
import crypto from 'crypto';
const algorithm = 'aes-256-gcm';
const key = Buffer.from(process.env.ENCRYPTION_KEY, 'hex');
const encrypt = (text) => {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
return {
encrypted,
iv: iv.toString('hex'),
authTag: authTag.toString('hex')
};
};
✅ Store sensitive config in env variables
// .env file (never commit to git)
JWT_SECRET=your-super-secret-key-here
DATABASE_URL=postgresql://user:pass@host:5432/db
ENCRYPTION_KEY=64-char-hex-key-here
Encryption Checklist:
- HTTPS everywhere (TLS 1.2+)
- Strong ciphers (AES-256-GCM)
- Encrypt PII at rest (credit cards, SSN)
- Environment variables for secrets
- Secrets management service (AWS Secrets Manager)
- Key rotation (change encryption keys regularly)
- Certificate pinning (mobile apps)
- HSTS header (force HTTPS)
6. Security Headers
Answer to interviewer:
"Security headers protect against common attacks. My configuration:"
✅ Using Helmet.js
import helmet from 'helmet';
app.use(helmet({
// Content Security Policy
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", "cdn.example.com"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'", "api.example.com"],
fontSrc: ["'self'", "fonts.googleapis.com"],
objectSrc: ["'none'"],
upgradeInsecureRequests: []
}
},
// Strict Transport Security (force HTTPS)
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
// Prevent clickjacking
frameguard: {
action: 'deny'
},
// Disable browser MIME sniffing
noSniff: true,
// XSS Protection
xssFilter: true
}));
Security Headers Checklist:
- Content-Security-Policy (CSP)
- Strict-Transport-Security (HSTS)
- X-Frame-Options (prevent clickjacking)
- X-Content-Type-Options (prevent MIME sniffing)
- X-XSS-Protection (XSS filter)
- Referrer-Policy (privacy)
- Permissions-Policy (feature control)
- CORS configuration (controlled access)
7. API Security
Answer to interviewer:
"APIs are attack vectors. My security approach:"
✅ Rate limiting
import rateLimit from 'express-rate-limit';
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per windowMs
message: 'Too many requests, please try again later'
});
app.use('/api/', apiLimiter);
✅ Input validation
import Joi from 'joi';
const userSchema = Joi.object({
email: Joi.string().email().required(),
password: Joi.string().min(8).required(),
age: Joi.number().integer().min(1).max(120)
});
app.post('/api/user', async (req, res) => {
const { error } = userSchema.validate(req.body);
if (error) {
return res.status(400).json({ error: error.details[0].message });
}
// Safe to process
});
✅ Request size limits
app.use(express.json({ limit: '10kb' })); // Max 10KB body
app.use(express.urlencoded({ extended: true, limit: '10kb' }));
API Security Checklist:
- Authentication (JWT, API keys)
- Rate limiting (per IP, per user)
- Input validation (Joi, express-validator)
- Request size limits
- Timeout handling
- CORS configuration
- API versioning (/api/v1/)
- Error handling (no info leakage)
- Logging & monitoring
- API documentation (OpenAPI/Swagger)
8. CORS Configuration
Answer to interviewer:
"CORS misconfiguration is a common vulnerability. Here's my setup:"
✅ Restrictive CORS (production)
import cors from 'cors';
const corsOptions = {
origin: ['https://myapp.com', 'https://www.myapp.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true, // Allow cookies
maxAge: 86400 // Cache preflight for 24 hours
};
app.use(cors(corsOptions));
✅ Dynamic origin validation
const corsOptions = {
origin: (origin, callback) => {
const allowedOrigins = ['https://myapp.com', 'https://admin.myapp.com'];
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true
};
app.use(cors(corsOptions));
⚠️ NEVER in production:
app.use(cors()); // Allows ALL origins!
9. Third-Party Dependencies
Answer to interviewer:
"Dependencies can introduce vulnerabilities. My security process:"
✅ Regular security audits
npm audit
npm audit fix
# Automated dependency scanning
npm install -g snyk
snyk test
snyk monitor
# Keep dependencies updated
npm outdated
npm update
Dependency Security Checklist:
- npm audit before every deploy
- Snyk or Dependabot for monitoring
- Review dependencies before adding
- Update regularly (monthly)
- Lock file committed (package-lock.json)
- Remove unused dependencies
- Use npm ci (not npm install) in CI/CD
- Check license compatibility
🎯 HOW TO ANSWER IN INTERVIEW
Performance Question
Interviewer: "How do you optimize website performance?"
Your answer (2-3 minutes):
"I approach performance holistically across frontend, backend, and network layers.
Frontend: I start with React optimization—React.memo for preventing re-renders, useMemo for expensive calculations, and code splitting with React.lazy. For a recent project, this reduced Time to Interactive from 4.2s to 1.8s.
Images are typically 50% of page weight, so I use WebP format, lazy loading, and CDN with automatic optimization. This improved our Largest Contentful Paint from 3.8s to 1.2s.
Backend: I implement 3-tier caching—CDN, Redis for application cache, and database query cache. This dropped API response time from 450ms to 12ms for cached data with an 87% cache hit rate.
Database: I ensure proper indexing—this alone improved a slow query from 2.3s to 48ms. I also use connection pooling and read replicas to scale reads from 1K to 10K queries/second.
Network: CDN is critical. I serve static assets from edge locations worldwide, reducing latency from 300ms to 20ms for international users.
I measure everything using Core Web Vitals and Lighthouse. In my last project, we achieved all 'Good' scores: LCP 1.8s, FID 45ms, CLS 0.05. This moved us from page 3 to page 1 in Google search, increasing organic traffic by 145%."
Security Question
Interviewer: "How do you secure a website?"
Your answer (2-3 minutes):
"Security is multi-layered. I follow the OWASP Top 10 and implement defense in depth.
Frontend: I prevent XSS by never using dangerouslySetInnerHTML unless the content is sanitized with DOMPurify. I implement Content Security Policy headers to block unauthorized scripts. For CSRF, I use SameSite cookies and CSRF tokens for state-changing operations.
Backend: SQL injection prevention is critical—I always use parameterized queries or ORMs like Prisma. Never string concatenation. I implement input validation with Joi or express-validator on every endpoint.
Authentication: I use JWT with short-lived access tokens (15 min) and longer refresh tokens (7 days) stored in HTTPOnly cookies. Passwords are hashed with bcrypt at cost factor 10. I implement rate limiting on login endpoints—5 attempts per 15 minutes—to prevent brute force attacks.
Encryption: All data in transit uses HTTPS with TLS 1.2+. Sensitive data at rest like credit cards are encrypted with AES-256-GCM. Secrets are stored in environment variables, never in code.
Security Headers: I use Helmet.js to set all security headers—CSP, HSTS, X-Frame-Options, etc. This protects against clickjacking, XSS, and other attacks.
API Security: Every API endpoint has rate limiting (100 requests per 15 min), authentication, and input validation. I also limit request body size to 10KB to prevent DoS.
Monitoring: I run npm audit before every deploy and use Snyk for continuous dependency scanning. I also implement logging and alerting for suspicious activities—multiple failed logins, unusual API patterns, etc.
In my last project, we passed a security audit with zero critical vulnerabilities and achieved SOC 2 Type II compliance."
📝 QUICK REFERENCE CHEAT SHEET
Performance (CRISP-LOAD)
- C - Code: React.memo, useMemo, code splitting
- R - Rendering: Virtual scrolling, startTransition
- I - Images: WebP, lazy loading, CDN
- S - State: Zustand, React Query, context splitting
- P - Progressive: SSR/SSG, service workers
- L - Lazy: Component/route lazy loading
- O - Output: Redis cache, CDN cache, query cache
- A - API: Pagination, field filtering, compression
- D - Database: Indexes, connection pooling, replicas
Security (SAFE-COAST)
- S - SQL: Parameterized queries, ORM
- A - Auth: JWT, bcrypt, rate limiting, 2FA
- F - Frontend: XSS prevention, CSRF tokens
- E - Encryption: HTTPS, AES-256, env variables
- C - CORS: Restrictive origin policy
- O - Output: Encoding, sanitization
- A - API: Rate limiting, validation, auth
- S - Security Headers: CSP, HSTS, X-Frame-Options
- T - Third-party: npm audit, Snyk monitoring
💪 Confidence Boosters
When talking about performance:
- "In my 13 years, I've optimized applications serving millions of users..."
- "I've reduced page load time by 70% multiple times by..."
- "Core Web Vitals are my benchmark—I always aim for all 'Good' scores..."
When talking about security:
- "Security is not optional—I follow OWASP Top 10 religiously..."
- "I've helped companies pass SOC 2 audits by implementing..."
- "Zero critical vulnerabilities in production is my standard..."
Impressive closing:
"I believe performance and security aren't afterthoughts—they're core to the development process. I build them in from day one, measure continuously, and iterate based on real metrics. That's how I've consistently delivered fast, secure applications in my 13 years of experience."
🎯 Practice this framework, and you'll impress any FAANG
interviewer! 🚀