Ionify vs Vite: What Actually Happens Inside Your Build Tool

Published: (April 7, 2026 at 03:24 PM EDT)
4 min read
Source: Dev.to

Source: Dev.to

Most developers use Vite and trust it. It’s fast, well‑designed, and gets out of the way.
But there’s a fundamental assumption baked into Vite’s architecture — and every other major build tool — that Ionify challenges.

The assumption: every build starts from zero.

The Stateless Build Problem

When you run vite build, roughly this happens:

  1. Vite spins up esbuild/Rollup (now often powered by Rolldown + Oxc).

  2. Each file goes through its plugin chain independently

    main.tsx   → TS plugin → JSX plugin → output
    utils.ts   → TS plugin → output
    index.css  → CSS plugin → output
  3. Everything gets bundled.

The next time you run it, the same process repeats. There’s no memory of what already ran; the TS plugin doesn’t know the JSX plugin already processed a file, and the bundler doesn’t know which files changed. The pipeline is stateless by design. This isn’t a bug — it’s a deliberate choice for simplicity and predictability, but it incurs a real cost at scale.

How Ionify Thinks About This Differently

Instead of repeatedly transforming files, Ionify addresses them.

Content‑Addressable Store (CAS)

Every module gets a content hash:

SHA-256(source content + config version) → CAS key

The result lives in a CAS directory:

.ionify/
  cas/
    /
      /
        transformed.js
        transformed.js.map

Same content + same config → same hash → skip the transform entirely. No transforms at all for unchanged modules.

The Persistent Graph

Vite reconstructs its module graph on every dev‑server start. Ionify persists it:

.ionify/
  graph.db   ← sled‑backed embedded KV store (Rust)

When a file changes, Ionify runs a BFS over the reverse‑dependency index to find exactly which modules are affected. In a 500‑module project, changing one utility file might invalidate only 12 modules, not all 500.

Version Isolation: Config Changes Invalidate Everything

A persistent cache must handle config changes. Ionify solves this with a deterministic version hash computed from the configuration, ensuring that any config modification invalidates the relevant caches.

The Four‑Tier CAS Architecture

As the system evolved, Ionify introduced four distinct caching layers, each solving a different problem.

Tier 1 — Module Transform Cache

Stores transformed module outputs keyed by the content hash.

Tier 2 — Deps Artifact Store

Caches compiled third‑party dependencies.

Tier 3 — Compression CAS

Pre‑compresses build outputs (Brotli‑11, gzip‑9) once, serving them forever.

Tier 4 — Chunk‑Output CAS

Caches final chunk files produced by the bundler.

Real Config: Migrating from Vite

Below is an example ionify.config.ts from a production project that switched from Vite:

import { defineConfig } from 'ionify'

export default defineConfig({
  entry: '/src/main.tsx',
  server: {
    https: true,
  },
  resolve: {
    // Same aliases as tsconfig — Ionify reads these natively
    // Note: if your tsconfig.json is JSONC (comments/trailing commas),
    // auto‑alias parsing currently fails — specify manually here
    alias: {
      '@@': '/',
      '@@/Core': '/Core/src',
      '@': '/src',
    },
    extensions: ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json'],
    conditions: ['import', 'module', 'browser', 'default'],
    mainFields: ['module', 'jsnext:main', 'jsnext', 'main'],
  },
  optimizeDeps: {
    include: ['moment-hijri'],   // pre‑warm known‑problem deps
    sharedChunks: 'auto',
    packSlimming: 'auto',
    vendorPacks: 'auto',
  },
  build: {
    target: 'esnext',
  },
})

The project contains over 10 k modules. After migrating to Ionify:

  • Cold build: 3.2 s (down from 3.7 s with Vite)
  • Warm build: 2.2 s (down from 3.7 s)

The Fundamental Difference

Build ToolCore Assumption
ViteEach build is independent.
IonifyMost of the work from the previous build is still valid.

Both assumptions are reasonable. Vite’s leads to a simpler, more predictable system. Ionify’s approach lets the second, tenth, and CI builds all benefit from prior work, leaving the “transform” side of the diagram mostly empty—not because complexity is hidden, but because most transforms simply don’t run.

Ionify is currently in production use.

0 views
Back to Blog

Related posts

Read more »