Configure for your environment
Generated code has to match how your project resolves imports. Find your environment below and copy the configuration.
The options involved are:
target: generate TypeScript (ts), or JavaScript with declarations (js+dts).import_extension: the file extension of relative imports between generated files.erasable_syntax: generate enums asas constobjects instead of TypeScriptenum.js_import_style: ESM or CommonJS, for JavaScript output only.
Your own imports of generated files follow the same rule as the generated code: if generated files import ./foo_pb.ts, import them the same way.
version: v2plugins: - local: protoc-gen-es out: src/gen opt: - target=ts - erasable_syntax=trueProjects created with create-vite enable erasableSyntaxOnly, which rejects TypeScript enums. erasable_syntax=true generates enums that pass.
This also applies to other bundlers: esbuild, Rollup, Parcel, and webpack.
Next.js
Section titled “Next.js”version: v2plugins: - local: protoc-gen-es out: src/gen opt: - target=ts - erasable_syntax=trueDo not use import_extension=js. Neither Turbopack nor webpack in Next.js resolves a .js import to a .ts file.
Node.js, running TypeScript directly
Section titled “Node.js, running TypeScript directly”Node.js runs .ts files natively since v22.18.
version: v2plugins: - local: protoc-gen-es out: src/gen opt: - target=ts - import_extension=ts - erasable_syntax=trueNode.js strips types but does not transform other TypeScript syntax, so enums must be erasable. It also does not map .js imports to .ts files, so imports need the .ts extension.
To type-check with tsc, use:
{ "compilerOptions": { "module": "nodenext", "noEmit": true, "allowImportingTsExtensions": true, "erasableSyntaxOnly": true, "verbatimModuleSyntax": true }}Node.js, compiling with tsc
Section titled “Node.js, compiling with tsc”version: v2plugins: - local: protoc-gen-es out: src/gen opt: - target=ts - import_extension=jsWith "module": "nodenext", TypeScript requires explicit extensions in ECMAScript modules, and resolves ./foo_pb.js to foo_pb.ts at compile time. The emitted JavaScript works in Node.js as is. This also works with tsx.
Node.js, JavaScript only
Section titled “Node.js, JavaScript only”version: v2plugins: - local: protoc-gen-es out: src/gen opt: - target=js+dts - import_extension=jsFor CommonJS, add js_import_style=legacy_commonjs.
version: v2plugins: - local: protoc-gen-es out: src/gen opt: - target=tsBun resolves imports with or without extensions and supports all TypeScript syntax, so any option works.
version: v2plugins: - local: protoc-gen-es out: src/gen opt: - target=ts - import_extension=tsDeno requires the real file extension in imports.