Open source · deploy

shipline: deploy only the functions your change touches

--only functions 83 redeployed · slow closure shipline affected 4–14 deployed · fast
deploy the closure of what changed — and never one function less

A single Firebase functions codebase has a tax you pay on every change: firebase deploy --only functions redeploys all of them, whatever you touched. It's slow, and on a heavy project it trips the Cloud Functions write-ops quota. shipline deploys only the functions your change actually affects — on the project it came from, a typical edit went from 83 functions to between 4 and 14.

Why: the all-or-nothing deploy

You change one domain module and Firebase rebuilds and redeploys the entire function set. The minutes add up, and past a certain size the deploy itself starts failing on quota. You could hand-maintain a wall of --only function-a,function-b,... flags, but that list rots the moment someone adds a require, and a stale list is worse than a slow deploy — it silently ships old code.

What shipline is

shipline reads each function's transitive require-closure from source and deploys only the functions whose closure includes a changed file. The critical property is that it is safe by construction: a targeted deploy leaves every unnamed function on its last-deployed code, so the resolver has to be provably complete — and when it can't prove completeness, it falls back to a full deploy rather than guess.

Never under-deploys. Change index.js, package.json, the lockfile, or .env → full deploy. A changed file no function reaches → full. A shared file reaching most functions → full, because that's cleaner than fifty flags. When the proof is uncertain, shipline ships everything. Speed never comes at the cost of correctness.

The watcher, and the incidents behind it

shipline watch is a fail-closed staging auto-deployer, and every guard in it is a production incident we only wanted to have once. The project id is explicit and must exist in .firebaserc — production stays promote-only, never an alias you can accidentally remap. A pre-deploy hook that fails never lets its target ship, because we once sent a stale bundle under a green log. Failures back off from 30 seconds to five minutes and write a loud line to a log file after three misses, because we once lost an hour to deploys silently not landing and scrollback is not a record. And it sets GOOGLE_CLOUD_QUOTA_PROJECT to your own project — the fix for the 429 that hits functions but not hosting, because firebase-tools bills its pre-check to a saturated shared quota.

Why it matters

Deploy friction quietly shapes how a team works: slow, risky deploys mean fewer, bigger, scarier ones. Make the deploy touch only what changed and prove it's safe, and shipping becomes something you do without flinching. That's the whole point — the boring infrastructure that lets everything else move fast.

shipline is open source (MIT). npm install -g shipline  ·  github.com/Doric-builder/shipline

The family it belongs to

shipline is the deploy line of four tools pulled from Doric's stack. keepline keeps an AI honest about facts, wireline catches code that's built but never wired, and plotline is the benchmark behind the first two. For the deploy philosophy in full, see why our agents run on real git branches.


← Back to all engineering notes

Ship the change, not the whole codebase.

View shipline on GitHub