The 5‑Minute Smoke Test I Run Before Every Push (and the one bug it missed)

I built a tiny, fast smoke-test suite that saves me CI minutes and ruined afternoons — how I picked the tests, wired them into hooks, and where it fails.

Written by: Arjun Malhotra

Person typing on a laptop with code visible on the screen and a coffee cup beside the keyboard
Photo by Brooke Cagle on Unsplash

It was 6:10 pm and I had one chance: a demo to a client at 7. I pulled a branch, made a small change, and my laptop — already struggling with an underpowered VM and a throttled home connection — started running the full test suite. Two hours later I had no demo, an annoyed product manager, and a new rule: never run the full suite before a push again.

We do plenty of right things at my startup — feature flags, staging, CI with protected branches — but the cost of running every test locally was real. My personal machine is a 2019 laptop with 8GB RAM. Our CI minutes are not free (we saw a ₹4,200 spike the month we kept rerunning flaky pipelines). Network is often slow at home. Waiting for everything to finish was wasting the one scarce resource I have after work: time.

So I built a 5‑minute smoke suite. Here’s how I chose what to run, how I wired it into my workflow, and the painful tradeoff that taught me its limits.

Why a smoke suite (and what “smoke” means to me) I needed something that’s fast, deterministic, and honest about “does this change obviously break the product?” Not “does any test in the repo fail?” — that’s CI’s job. My smoke suite runs in under five minutes on my laptop and checks the things most likely to explode on a push: app bootstrap, main API endpoints, critical DB queries, auth flows, and a UI snapshot or two for the component I touched.

Concrete rule I followed when picking tests:

How I built it (tools and wiring) I already had tests in Jest and pytest. I didn’t want a new framework. I annotated tests with a “smoke” tag/marker and put a tiny runner script in the repo root.

Then I wired tests/smoke.sh into a pre-push Git hook (husky for JS, just a .git/hooks script for others). The hook runs the smoke suite and blocks the push if it fails. It returns fast if unchanged files don’t touch backend code (I check git diff —name-only HEAD..HEAD~1 to avoid needless runs).

This combo bought me three things immediately:

The honest failure (and the limitation I had to accept) Two months in, smoke tests gave me a clean push and confidence. CI went green. I merged. The next day, a merchant complained that payouts stalled. The bug? A background job that reconciles payments on a nightly cron missed a schema change. My smoke suite never touched the nightly worker or the edge-case DB migration because those were slow, async, and involved message queues that are painful to run locally.

There are two lessons from that incident:

Tradeoffs I accepted

Practical tips if you want one

What I actually walked away with The single thing that changed my day-to-day: I stopped treating pre-push tests as “optional comfort” and made them a small, enforced habit. That bought me predictable demos, fewer late-night CI runs, and calmer afternoons. But the payment bug taught me that a fast safety net can make you careless about deeper coverage. The next problem to solve for me is automating the scheduled-worker tests into CI so a nightly task can’t be a blind spot again.

I don’t know the perfect balance. But if you’re juggling a slow laptop, a small CI budget, and demos at odd hours — build a smoke suite that tells you, fast, whether your change is obviously broken. Then keep the rest of your tests sacred and automated in CI.