DEV Community

KhaledSalem
KhaledSalem

Posted on

I built a build engine that remembers. Here's what happened.

We've been optimizing the wrong thing.

Vite made builds fast. Webpack made builds structured. Everyone declared victory and moved on.

But nobody asked the question that's been bothering me for years:

Why does every build start from zero?

Not as a philosophical exercise. As a real engineering problem.

Your dependency graph didn't change. Your packages didn't change. 90% of what your build tool is about to do — it already did last week. On this machine. And on every other machine on your team.

But it rebuilds anyway because it doesn't remember.


So I built something that does.

Ionify is a frontend build engine with one core architectural difference from every tool you've used before:

The dependency graph persists.

Not in RAM. Persisted and shared — across runs, across dev and build, across every machine on your team.

// Every other tool
run build
  → build a graph in memory
  → use it
  → destroy it  ❌

// Ionify
run build
  → load graph from disk
  → update only what changed
  → save back  ✅
Enter fullscreen mode Exit fullscreen mode

That one change cascades into everything else.


What actually changes

Content-addressable artifacts

Every output is stored by its content hash. If the content didn't change, the artifact already exists. No rebuild. No retransform. Just reuse.

This works across machines. Your CI doesn't recompute what your dev already computed.

Route-aware vendor packs

The persistent graph accumulates route history. It knows which dependencies appear together at runtime. It groups them accordingly.

Before vendor packs:
  requests: 46    bytes: 1.8 MB    parse time: baseline

After:
  requests:  9    bytes: 420 KB    parse time saved: 120ms
Enter fullscreen mode Exit fullscreen mode

80% fewer requests. 76% fewer bytes. Not from HTTP/2 tricks. From the engine knowing your app better than a single build ever could.

Pre-compressed output

Vite's model: emit raw assets, let nginx compress at request time. At Brotli quality 11, that's too slow for per-request use, so servers use br:4–6. That's 15–30% larger than maximum compression.

Ionify emits .br and .gz sidecars at build time at maximum quality (br:11, gz:9). The server reads pre-built bytes directly.

Request-time CPU:      zero
Brotli quality:        br:11 (maximum)
Warm rebuild cost:     3ms (CAS hit)
Enter fullscreen mode Exit fullscreen mode

The benchmark that surprised me

After fixing three parallelization issues in the build pipeline:

Before:
  cold: 144ms

  ↓ Fix 1: parallel CAS restore (br+gz)    → -35ms
  ↓ Fix 2: eager hash hint                 → -10ms
  ↓ Fix 3: parallel collectFilesRecursive  → -47ms net

After:
  cold: 52ms ✅
Enter fullscreen mode Exit fullscreen mode

And the full comparison:

Ionify cold:  52ms   (full precompression included)
Vite cold:   111ms   (no precompression at all)

Ionify warm:  30ms   (CAS hits + sidecar reuse)
Vite warm:   110ms   (full retransform every time)
Enter fullscreen mode Exit fullscreen mode

Warm at 30ms isn't clever caching. It's the engine verifying previous work is still valid and reusing it. Vite retransforms everything because it has no way to know.


On the browser side

When you ship a bugfix, a Vite user's browser re-downloads the full 479 KB bundle. The vendor code, the React runtime, the shared utilities — all of it. Because from Vite's perspective, a build happened and the output changed.

On the second visit after any deploy: Ionify transfers ~10 KB. Vite transfers 479 KB.


The architectural table nobody shows you

Webpack Vite Ionify
Persistent graph
CAS artifacts
Route-aware packs
Same engine dev+build
Pre-compressed (br:11)
Analysis lifetime per-run per-run persistent
Gets faster over time

What this isn't

This isn't "Vite is bad." Vite is an excellent escape from Webpack and HMR optimization since that time. But frontend grew into a system, and systems need engines, not just tools.

Tools are built for a moment. Engines are built for systems.
That's where Ionify lives.

Single machine → modest improvement.
Multi-machine CI + shared deps + many routes → the gap becomes structural.

At that point, you're not comparing tools. You're comparing whether your build infrastructure has memory or not.


Try it

GitHub: github.com/ionify/
Docs: ionify.cloud

If this resonates, a star goes a long way. And I'd genuinely love to hear if you've hit the same wall.

What's your current build time on a warm run?

Top comments (0)