>_DevLog
Writing Vite Plugins: A Developer Guide
2026-03-05
Vite's plugin API is built on top of Rollup's, with Vite-specific hooks added on top. This guide walks through building a plugin from scratch.
Plugin Basics
A Vite plugin is a plain object with a name and one or more hook functions:
import type { Plugin } from 'vite'
export function myPlugin(): Plugin {
return {
name: 'my-plugin',
transform(code, id) {
if (!id.endsWith('.ts')) return
// transform source code
return code.replace('__VERSION__', '1.0.0')
},
}
}
Common Hooks
| Hook | When it runs |
|---|---|
config |
Modify the Vite config |
configResolved |
Read the final resolved config |
transform |
Transform a module's source |
resolveId |
Resolve a module id to a path |
load |
Load a virtual module |
buildStart |
Before the build begins |
generateBundle |
After bundles are generated |
Virtual Modules
Virtual modules are files that don't exist on disk but can be imported:
const virtualId = 'virtual:config'
const resolvedId = '\0' + virtualId
export function configPlugin(): Plugin {
return {
name: 'virtual-config',
resolveId(id) {
if (id === virtualId) return resolvedId
},
load(id) {
if (id === resolvedId) {
return `export const config = ${JSON.stringify({ env: 'production' })}`
}
},
}
}
Dev-Only vs Build-Only
Use apply to restrict a plugin to a specific phase:
{ apply: 'serve' } // dev server only
{ apply: 'build' } // production build only
Vite's plugin system is surprisingly approachable — most useful plugins are under 100 lines of code.