0x.run

Tech tutorials, programming guides, and developer resources

OAuth 2.0 Explained Without the Jargon

OAuth 2.0 lets users grant apps access to their data without sharing passwords. Use Authorization Code flow for web apps, PKCE for SPAs and mobile, Client Credentials for server-to-server. Never store tokens in localStorage.

Zero-Downtime Database Migrations

Zero-downtime migrations use backward-compatible steps. Add columns nullable first. Deploy code that handles both schemas. Backfill data in batches. Add constraints. Never rename or drop in one step—use expand and contract.

Feature Flags: Ship Code Without Breaking Things

Feature flags are runtime toggles that control what code runs. Use them for gradual rollouts, A/B tests, kill switches, and beta access. Store in Redis or database, not config files. Kill switches save production incidents.

The JavaScript Event Loop Isn't Magic

JavaScript runs on a single thread with an event loop. Synchronous code runs to completion. Async callbacks wait in queues. Microtasks (Promises) run before macrotasks (setTimeout). Blocking the call stack freezes everything.

Postgres Full-Text Search: Skip Elasticsearch for Most Apps

PostgreSQL full-text search uses tsvector and tsquery. Index with GIN indexes. Use ts_rank for relevance, websearch_to_tsquery for user input, and pg_trgm for fuzzy matching. Handles millions of records well with no extra infrastructure.

HTTP Caching Headers: Cache-Control Explained

Cache-Control headers tell browsers and CDNs how long to store responses. Use max-age for static assets, no-cache for HTML, private for user data, immutable for versioned files. ETags enable conditional requests that skip downloading unchanged content.

Webhooks: How to Build Reliable Event Delivery

Webhooks are HTTP POST requests triggered by events. Verify signatures to prevent spoofing. Return 200 immediately, process async. Retry with exponential backoff. Store delivery logs. Use queues for reliability.

ACID Transactions: What They Actually Mean in Practice

ACID guarantees that database operations are Atomic (all or nothing), Consistent (rules enforced), Isolated (concurrent transactions don't interfere), and Durable (committed data survives crashes). Without transactions, concurrent writes corrupt data.

Graceful Shutdown: Why Your App Crashes on Deploy

Graceful shutdown drains in-flight requests before stopping. Catch SIGTERM, stop accepting new connections, wait for active requests to finish, then exit. Without it, every deploy drops requests and breaks transactions.

WebSockets in Production: Handling Disconnects and Scaling

WebSockets enable real-time bidirectional communication. Handle reconnection with exponential backoff. Use heartbeats to detect dead connections. Scale with Redis pub/sub. Store connection state. Close connections properly.

Docker Multi-Stage Builds: From 1.2GB to 100MB

Multi-stage builds use multiple FROM statements. Build stage has compilers and tools. Final stage has only runtime dependencies. Result: 10x smaller images, faster deploys, fewer vulnerabilities. Copy artifacts between stages.

Debouncing vs Throttling: When to Use Each

Debouncing waits until user stops (search input). Throttling limits rate (scroll handler). Debounce = last call wins. Throttle = regular intervals. Use debounce for user input, throttle for continuous events.

Regular Expressions: The 10 Patterns You Actually Use

Learn 10 regex patterns: email, URL, phone, credit card, password strength, whitespace, special chars, numbers, dates, and file extensions. Test on regex101.com. Use named groups. Avoid catastrophic backtracking.

Date and Time: Common Pitfalls and How to Fix Them

Always store dates in UTC. Display in user's timezone. Never use new Date() for parsing. Avoid date math with native Date. Use date-fns or Luxon. ISO 8601 for serialization. Timezones are hard - libraries handle them.

Building a Simple In-Memory Cache with TTL

Cache = store expensive results in memory. Add TTL to expire old data. Use LRU to limit memory. Check cache before expensive operations. 10x-100x speed improvement for repeated data.

Message Queues: RabbitMQ vs Redis vs SQS

Use RabbitMQ for complex routing and guaranteed delivery. Use Redis for simple, fast queues. Use SQS for managed, scalable queues on AWS. All handle async tasks - choose based on complexity, scale, and infrastructure.

Load Testing: Finding Your Breaking Point Before Users Do

Load test before launch. Use k6 or Artillery to simulate traffic. Test realistic scenarios, not just homepage. Find your breaking point. Monitor CPU, memory, database connections. Fix bottlenecks before users find them.

XSS Attacks Explained: How to Prevent Cross-Site Scripting

XSS happens when user input is rendered as HTML/JavaScript. Escape all output. Use textContent not innerHTML. Sanitize HTML with DOMPurify. Enable Content Security Policy. React/Vue escape by default - don't use dangerouslySetInnerHTML.

SQL Injection: How It Happens and How to Prevent It

SQL injection happens when user input goes directly into SQL queries. Never concatenate user input into SQL. Use parameterized queries, prepared statements, or ORMs. Validate input. Escape output. Test with SQLMap.

The N+1 Query Problem: How to Detect and Fix It

N+1 queries happen when you fetch records in a loop - 1 query becomes 1000. Detect with query logging and APM tools. Fix with eager loading, joins, or batching. 100x performance improvement is common.

Logging in Production: What to Log, What to Skip

Use structured logging with levels. Log requests, errors, and key events - not sensitive data or debug spam. JSON format for aggregation. Keep performance impact under 5%. Fix log leaks before they become breaches.

REST API Error Handling: The Right Way

Use proper HTTP status codes. Return consistent error format with code, message, and details. Log errors server-side. Never expose stack traces to clients.

API Versioning: URL vs Header vs Query Parameter

URL versioning (/v1/users) is simplest and most discoverable. Header versioning is cleaner but harder to use. Start with URL versioning, only use headers if you have a strong reason.

Background Jobs and Queues: Stop Blocking Your API

Never block API responses with slow operations. Use job queues for emails, image processing, reports. Bull with Redis is simple and reliable. Process jobs in workers, not request handlers.

Rate Limiting Algorithms Explained with Code

Rate limiting prevents API abuse. Token bucket is most flexible, fixed window is simplest, sliding window is most accurate. Implement in-memory for single servers, Redis for distributed systems.

Database Indexes Explained: The Only Guide You Need

Indexes make queries fast by avoiding full table scans. But too many indexes slow down writes. Use EXPLAIN to identify slow queries, add indexes on WHERE/JOIN columns, and avoid indexing everything.

Your Startup Doesn't Need Microservices

Microservices add operational complexity that small teams can't afford. Monoliths are faster to build, easier to debug, and simpler to deploy. Split services when you have a reason, not because it's trendy.

Why I Write SQL Instead of Using ORMs

ORMs hide complexity that eventually bites you. Raw SQL is explicit, performant, and easier to debug. Use ORMs for CRUD, write SQL for anything complex.

UUID v7: The New UUID That Actually Makes Sense

UUID v7 puts timestamps at the beginning, making database indexes happy. I saw 3x better insert performance and 50% smaller indexes after migrating. Here's how and when to switch.

CORS Errors: Every Fix That Actually Works

CORS errors are never quite the same. Here's every fix I've used in production, why each error happens, and actual code you can copy-paste for your specific situation.

Why I Stopped Using Frameworks for Everything

Frameworks solve real problems but add complexity. Use them when they solve problems you actually have, not because they're trendy. Sometimes vanilla code is faster to write and maintain.