Get in touch
Engineering

Shipping faster with less

We took eleven minutes off the build by deleting things. Here is what went, what stayed, and the one rule we now apply before adding anything back.

By Ovadev3 min read

All posts
  • build
  • tooling
  • ci

A build gets slow the way a room gets full: nobody ever decides to fill it. Ours went from four minutes to fourteen over about a year, one reasonable addition at a time, and every one of those additions had a good argument behind it on the day it landed.

In April we stopped adding and started reading. Not profiling — reading. Every step in the pipeline, out loud, with the question what breaks if this is gone. Two thirds of the answers were some version of “nothing, but it feels safer.”

before
14:20

median CI run, main branch

after
3:05

same commit range, same runner

build tools
6 → 2

counting anything with its own config file

What actually cost the time#

The honest answer was not the compiler. It was the layers around it — a wrapper that existed to configure the bundler, a second test runner kept for one legacy suite, a lint pass that ran again inside the type-check because nobody was sure the first one had.

StepBeforeAfter
Install3:100:40
Lint2:050:25
Type-check1:501:05
Test4:350:55
Build2:40
Median of twenty runs before and after, on the same machine class.

The build row is empty because the build now happens inside the deploy, once, instead of twice in CI and again on the platform. That was the single largest win and it came from deleting a job, not from tuning one.

The install was the easy half#

Moving to pnpm with a locked store took the install from three minutes to forty seconds, and it did it by not copying: a content-addressed store plus hard links means the second install of the same dependency is a link, not a download.

bash
# what the runner does now, in full
corepack enable
pnpm install --frozen-lockfile
pnpm lint && pnpm typecheck && pnpm test
The whole CI script. If it needs a comment, it needs deleting.

The rule we kept#

Deleting is easy once. Staying deleted is the hard part, because the next tool always arrives attached to a real problem. So we wrote down the test it has to pass, and it is deliberately annoying to satisfy:

  1. 01
    Name the failure

    Which specific bug reached production, or would have? “Best practice” is not a failure. If nobody can point at the incident, the tool is insurance against an imagined risk.

  2. 02
    Name what it replaces

    Additive tooling compounds. Anything new either takes over a step or it does not come in — two linters is a decision nobody ever makes on purpose.

  3. 03
    Name its budget

    Seconds of CI time, and a number we check a month later. A step that outgrows its budget goes back to review instead of quietly becoming the new normal.

Three tools have been proposed since. One passed. That ratio feels about right — the goal was never zero tools, it was tools that can each explain themselves.

Ovadev

A software company in Baar, Zug. We build our own products, run them afterwards, and write down what that teaches us.

Get in touch
Read next

More from the studio — engineering first, then the rest of the feed.

All posts
© 2026 Ovadev GmbHMade in Switzerland