# git push production deploy: Skip the 9-Minute CI Queue

> Skip the CI queue: one git remote, one hook, and your Next.js app reloads in 20 seconds with zero downtime. Setup inside.

Source: https://boringpush.com/blog/git-push-production-main-deploy

## Shipping needs a browser tab

Somewhere along the way, deploying a solo side project started requiring a CI pipeline: push to GitHub, wait for runners, watch a YAML workflow turn green, then click through a dashboard to promote the build.

For a team of thirty, that machinery earns its keep. For one founder fixing a pricing typo from the couch, it is a queue between the idea and the user.

The git push production deploy deletes the queue. Your laptop is the CI.

The VPS is the target. Nothing in between bills you.

## What the pipeline actually costs you

| Cost | GitHub Actions + platform | git push production deploy |
|---|---|---|
| Wait per ship | 3–12 min queue + build | ~20 s build on the box |
| Monthly meter | Minutes × runners, then overages | $0 — the $5 box builds |
| Config surface | YAML workflows, secrets, OIDC | One remote + one 15-line hook |
| Debug path | Scroll runner logs in a browser | Read the hook output in your terminal |
| Offline failure | No push without GitHub up | LAN + Tailscale still ships |

Three details sting more than the invoice:

1. **Small fixes stop shipping.** When every typo costs a 9-minute pipeline, you batch five fixes into Friday. Friday batches break more than Tuesday one-liners.
2. **Mixed architectures break in the cloud.** A native module built for your Mac's chip, rebuilt on a runner for Linux, can turn green checks into segfaults at midnight. Fewer hops between your machine and the server shrink that class of surprise.
3. **The gate runs far from the truth.** Lint passes on the runner, then the app dies because the server's settings drifted three deploys ago. A deploy that uses the server's own settings file cannot drift from itself.

None of this insults CI. Teams that need approvals, matrices, and audit trails should keep it. Founders who need speed should push.

## One command, one health check, one reload

BoringPush ships this loop as `bp deploy`. The older `git push production main` flow remains supported as a fallback when direct SSH is not available. Total setup: ten minutes, once.

**Step 1: Point the kit at your server.** The one-time server setup creates a deploy remote called `production` and prepares the machine. After that, deploying is one command from your laptop. Because your server's private hostname works from couch Wi-Fi, 5G or a hotel captive portal with no open ports, you can run it from anywhere you can reach the server. The checks run before anything leaves: a syntax check and a zero-warning lint run on your own machine, in seconds.

**Step 2: Build once, ship the result.** `bp deploy` compiles the app on your laptop and sends the finished build to the server over SSH. The server swaps it in, keeping the previous build beside it. Building on your own machine means a small server never runs out of memory in the middle of a build, and there is no runner image to pin.

**Step 3: Reload and verify.** The server reloads the app and waits until the new version is actually serving before the command finishes. If the new version never answers, the old one is put back. Visitors on the old process finish while the new one boots, and long checkouts survive the deploy they overlap. One honest caveat from reading the code: when the server undoes a bad release itself, the command on your side may still look as if it finished, so read the output and open the site.

That's what all of this buys: the phone types the fix, and the same command ships it.

## The fast deploy

| Check | Action | Pass looks like |
|---|---|---|
| Server reachable | `bp status` | Branch, database size and latest backup listed |
| Deploy asks first | Run `bp deploy` in a terminal | It shows the branch and commit, then asks |
| Ship time | Time a small change end to end | Seconds to a minute, no CI queue |
| Users unaffected | Reload the site during a deploy | Pages keep loading |

The flip side, honestly: one writer at a time. Two founders deploying in the same second can interleave, so agree on who ships. BoringPush also keeps the previous build one command back, so a bad deploy rolls back with `bp rollback --yes` in seconds.

If you outgrow the loop, with staging environments, required reviews or matrix builds, add CI in front later. The deploy command stays as the last mile. Starting with the pipeline is buying a bus for one passenger.

## FAQ

### Does a command-line deploy work from my phone?

Yes, that is the point. Your SSH app opens the server over a private network, and the same deploy runs from the phone keyboard.

Small fixes ship from the couch in minutes. The first post in this series covers the full phone setup.

### What if the build fails halfway? Is the site down?

No. The build happens on your machine before anything is sent, so a failed build never reaches the server.

The old code keeps serving. You read the error in your terminal, fix it and run the deploy again.

### How do preview branches or staging fit in?

Run a second copy of the app on the same server under a staging subdomain, with its own deploy target. Deploy to staging to preview, then to production to ship.

No per-seat preview pricing and no new services. The kit does not wire this up for you automatically.

### Where do secrets live if there is no CI vault?

In the settings file on the server, synced with `bp secret sync` and never committed. The deploy uses the server's own file, so deploys cannot drift from secrets. Rotate by changing one file and syncing, with no vault UI.

### Can two founders share one production target?

Yes, with a rule: ship one at a time. Each founder connects over their own private network identity.

For more than three writers, graduate to CI. The deploy command remains the last mile either way.

### What about database migrations during a deploy?

Additive only, applied deliberately by a person. `bp db check` scans a migration file for destructive statements first, and production migrations are never run by an agent. Adding a column is safe against live traffic, and drops and renames are never part of a deploy.

## Keep reading

- [Deploy Next.js on Hetzner $5 by Dinner Tonight](/blog/deploy-nextjs-hetzner-vps) — the afternoon build this remote lands on
- [Cloudflare Tunnel + Next.js: Hackers Find Zero Open Ports](/blog/cloudflare-tunnel-nextjs-vps) — the closed-door box your push ships to
- [How to Ship Code From Your Phone (2026 Setup)](/blog/ship-code-from-phone) — the 4-app stack for pushing from anywhere
