Summary
@google/genai ships a working CommonJS bundle (added in #605, v1.1.0), but the exports map declares one types entry shared by both the import and require conditions. Because package.json sets "type": "module", TypeScript treats that .d.ts as an ES module, so a CommonJS consumer is told the package cannot be require()d — even though require() resolves to a real .cjs file and works perfectly at runtime.
This is the type-level half of #605 that never landed. It's also, I believe, the actual root cause of #648, which was closed with a "set type: module" workaround rather than a fix — that thread has a second user asking how to solve it and the original reporter ending with "I switched to this one package" (openai-node). So this is quietly costing you TypeScript CJS users.
Environment
@google/genai 1.52.0
typescript 6.0.3 (also reproduces on 5.x)
- Node 22.22.2
- Consumer is CommonJS (no
"type": "module"), module/moduleResolution: node16 (same on nodenext)
Minimal reproduction
package.json
{ "name": "genai-cjs-repro", "version": "1.0.0", "private": true }
tsconfig.json
{
"compilerOptions": {
"module": "node16",
"moduleResolution": "node16",
"target": "es2022",
"strict": true,
"noEmit": true
},
"include": ["src"]
}
src/index.ts
import { GoogleGenAI } from '@google/genai';
const client = new GoogleGenAI({ apiKey: 'x' });
npm i @google/genai@1.52.0 typescript@6.0.3
npx tsc -p tsconfig.json
Actual
src/index.ts(1,29): error TS1479: The current file is a CommonJS module whose imports will
produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be
imported with 'require'. Consider writing a dynamic 'import("@google/genai")' call instead.
Type-only imports fail too, with:
error TS1541: Type-only import of an ECMAScript module from a CommonJS module must have a
'resolution-mode' attribute.
But the runtime is fine
In that same project, require() resolves to the CJS bundle and instantiates correctly:
$ node -e "const p=require.resolve('@google/genai'); const {GoogleGenAI}=require('@google/genai');
console.log(p.split('/node_modules/')[1], typeof GoogleGenAI, typeof new GoogleGenAI({apiKey:'x'}))"
@google/genai/dist/node/index.cjs function object
So this is purely a types-packaging gap, not a runtime incompatibility. Nothing here relies on Node's require(esm) support.
Cause
dist/node/ contains index.mjs, index.cjs, and only node.d.ts — there is no node.d.cts. The current condition:
"node": {
"types": "./dist/node/node.d.ts",
"import": "./dist/node/index.mjs",
"require": "./dist/node/index.cjs",
"default": "./dist/node/index.mjs"
}
With "type": "module" at the package root, node.d.ts is an ESM declaration file, and TypeScript has no CJS type view to pair with the require target.
Suggested fix
Emit a CJS declaration file and select types per condition, so each resolves to a declaration whose module kind matches its target:
"node": {
"import": {
"types": "./dist/node/node.d.ts",
"default": "./dist/node/index.mjs"
},
"require": {
"types": "./dist/node/node.d.cts",
"default": "./dist/node/index.cjs"
}
}
(Same treatment for the root . entry, which has the identical shape.) This is the standard dual-publish layout and would make TS1479/TS1541 disappear for CJS consumers with no change on the ESM side and no API change.
Workarounds today, for anyone hitting this
- Type-only imports work with an explicit resolution mode:
import type { GoogleGenAI } from '@google/genai' with { 'resolution-mode': 'import' };
- A value import needs
await import('@google/genai'), which forces the acquiring function to be async — awkward when the client is built in a constructor or property initializer, as it can't be awaited there.
Summary
@google/genaiships a working CommonJS bundle (added in #605, v1.1.0), but theexportsmap declares onetypesentry shared by both theimportandrequireconditions. Becausepackage.jsonsets"type": "module", TypeScript treats that.d.tsas an ES module, so a CommonJS consumer is told the package cannot berequire()d — even thoughrequire()resolves to a real.cjsfile and works perfectly at runtime.This is the type-level half of #605 that never landed. It's also, I believe, the actual root cause of #648, which was closed with a "set
type: module" workaround rather than a fix — that thread has a second user asking how to solve it and the original reporter ending with "I switched to this one package" (openai-node). So this is quietly costing you TypeScript CJS users.Environment
@google/genai1.52.0typescript6.0.3 (also reproduces on 5.x)"type": "module"),module/moduleResolution:node16(same onnodenext)Minimal reproduction
package.json{ "name": "genai-cjs-repro", "version": "1.0.0", "private": true }tsconfig.json{ "compilerOptions": { "module": "node16", "moduleResolution": "node16", "target": "es2022", "strict": true, "noEmit": true }, "include": ["src"] }src/index.tsActual
Type-only imports fail too, with:
But the runtime is fine
In that same project,
require()resolves to the CJS bundle and instantiates correctly:So this is purely a types-packaging gap, not a runtime incompatibility. Nothing here relies on Node's
require(esm)support.Cause
dist/node/containsindex.mjs,index.cjs, and onlynode.d.ts— there is nonode.d.cts. The current condition:With
"type": "module"at the package root,node.d.tsis an ESM declaration file, and TypeScript has no CJS type view to pair with therequiretarget.Suggested fix
Emit a CJS declaration file and select
typesper condition, so each resolves to a declaration whose module kind matches its target:(Same treatment for the root
.entry, which has the identical shape.) This is the standard dual-publish layout and would make TS1479/TS1541 disappear for CJS consumers with no change on the ESM side and no API change.Workarounds today, for anyone hitting this
await import('@google/genai'), which forces the acquiring function to be async — awkward when the client is built in a constructor or property initializer, as it can't be awaited there.