← Back to Blog

Two alias shapes: Vite resolve.alias vs Turbopack resolveAlias

·6 min read

The alias that fixes the node_modules resolution gap is nearly identical across Vite and Next.js Turbopack, but "nearly" hides a real design difference. The two bundlers express the same concept in different homes, and pyrpc has to speak both dialects.

The two forms, side by side

// Vite, lives under resolve
resolve: {
  alias: { "@pyrpc/types": "./__pyrpc.ts" }
}

// Next.js Turbopack, lives under turbopack
turbopack: {
  resolveAlias: { "@pyrpc/types": "./__pyrpc.ts" }
}

Both map a bare specifier to a file. But their placement reflects each bundler's mental model of what an alias is.

Vite: aliases are a resolution concern

Vite treats aliasing as part of module resolution, grouped with extensions and dedupe under resolve. Vite's alias also accepts object shorthand where the value may be a string or an { find, replacement } pair for regex-based matching. The simple string form pyrpc emits is the object shorthand, one package name, one target.

Turbopack: aliases are a bundler feature

Next.js's Turbopack mode scopes the alias under a top-level turbopack key, because Turbopack is one of several runtimes a single next.config.js can target. The resolveAlias key is Turbopack's own name for the same idea, webpack's resolve.alias counterpart, namespaced so webpack mode and Turbopack mode can coexist in one config.

What this means for codegen

Because the two dialects have different parent keys, the injection logic must branch on the detected framework, which is exactly why _inject_vite and _inject_next are separate functions sharing the same splice machinery. The shared part is the hard-won generality: both still reduce to find the config object, append a property. The divergent part is just the snippet text.

The general lesson

Cross-tool automation is a Rosetta stone problem: the same semantic (alias this package to this file) has a different syntax in every tool. The pragmatic structure is a shared mechanical core plus a per-tool snippet table. When a new bundler arrives, you add an entry to the signature map, write one snippet, and reuse the splice, the table grows, the machinery does not.