The Daily
A note a day on APIs and the realities of shipping web applications. Stuff I've actually learned across 25 years of doing the work.
Structured Laravel Logging You Can Actually Query (No Datadog Required)
You don't need a $500/month observability platform to query your logs. Here's how I set up structured logging on a single VM that doesn't make me want to grep through walls.
Most single-VM Laravel apps I inherit have the same log setup: the default channel, a wall of unstructured text in , and a developer who's been doing and hoping for the best. That's fine until something breaks at 2am and you're staring at a 400MB log file trying to correlate a user ID across five different request…
Read the daily →Shaving 600MB off a Laravel Image with Multi-Stage Builds
Multi-stage Docker builds aren't magic — they're a scalpel. Here's what they actually copy, what they silently skip, and how I got a Laravel image from 980MB to 340MB.
I spent an embarrassing amount of time thinking multi-stage Docker builds were basically magic — build your stuff in one container, copy it to another, done, small image. Then I deployed a Laravel app to a client's VPS and watched the image clock in at 980MB. That's when I actually sat down and read what does and…
Read the daily →SQLite as Your Laravel SaaS DB: Where It Holds Up and Where It Breaks
I ran SQLite as the primary database on a real single-tenant Laravel app. Here's what actually happened when the load got serious.
SQLite in production gets dismissed immediately by most people who've never actually tried it for a real workload. I was one of those people — until a client situation forced my hand, and it worked better than I expected for longer than I expected. Then it didn't. Here's the honest version. The Setup That Got Me Here…
Read the daily →Self-hosted GitHub Actions runners on a $10 VPS: worth it, with caveats
Running GitHub Actions on your own VPS cuts CI costs to near zero. Here's the setup I use and the gotchas that will bite you if you skip the boring parts.
GitHub's hosted runners are convenient right up until you're paying $50/month for a Laravel app with a modest test suite. I moved several client projects to self-hosted runners on a $10 DigitalOcean Droplet and cut that bill to essentially zero. The setup takes about an hour. The gotchas take longer to find. Why…
Read the daily →Stripe Metered Billing: Building a Usage Ledger That Survives Out-of-Order Webhooks
Stripe's metered billing webhooks don't arrive in order. Here's how I built an idempotent usage ledger that doesn't double-charge customers when they don't.
Stripe's metered billing is genuinely useful until the first time you realize webhooks don't arrive in chronological order — and your usage ledger has silently double-counted 40% of a customer's API calls. I learned this the hard way building a usage-based billing system for a biotech client running genomics…
Read the daily →