Skip to content

Decimal field generates broken import { Prisma } from "@prisma/client" when using a custom Prisma Client output path #3448

Description

@Hoegsgaard

Describe the bug

When a Prisma model has a Decimal field, @tsed/prisma always generates import { Prisma } from "@prisma/client" in the model class. That import is hardcoded to the default @prisma/client location, no matter where the Prisma Client is actually generated. If generator client uses a custom output path (which is Prisma's own recommended default as of v7, not some niche setup), that import points at nothing and the app crashes on load.

Looks like an oversight, not something unsupported by design. generateClientIndex.ts already resolves the client path correctly:

// packages/orm/prisma/src/generator/utils/generateClientIndex.ts
const moduleSpecifier = resolveExtension(
  options.prismaClientPath.includes("@prisma/client")
    ? options.prismaClientPath
    : `../${options.prismaClientPath}/index`
);

But transformScalarToType.ts's Decimal handling doesn't have access to prismaClientPath and just hardcodes it:

// packages/orm/prisma/src/generator/transform/transformScalarToType.ts
if (field.type === PrismaScalars.Decimal) {
  field.model.addImportDeclaration("@prisma/client", "Prisma");
}

TransformContext never carries that path, so there's currently no way for this function to resolve it correctly.

To Reproduce

Minimal schema.prisma, sqlite, no real DB needed. Tested against a clean install of exactly these versions.

generator client {
  provider = "prisma-client-js"
  output   = "../generated/prisma"
}

generator tsed {
  provider           = "tsed-prisma"
  output             = "../generated/tsed"
  emitTranspiledCode = true
}

datasource db {
  provider = "sqlite"
}

model Product {
  id    Int     @id @default(autoincrement())
  price Decimal
}

prisma.config.ts just needs schema: 'prisma/schema.prisma', no DATABASE_URL needed for generate. sqlite doesn't support @db.Decimal(...) but the bug reproduces fine without a native type, it's the bare Decimal scalar that triggers it.

npx prisma generate
node -e "import('./generated/tsed/index.js').then(() => console.log('ok'))"

Expected behavior

Import resolves fine. The Prisma import should point at the actual configured client output, same as generateClientIndex.ts already does for the client re-export.

Code snippets

Generated generated/tsed/models/ProductModel.js:

import { Prisma } from "@prisma/client";

Via node -e "import(...)":

Named export 'Prisma' not found. The requested module '@prisma/client' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from '@prisma/client';
const { Prisma } = pkg;

Requiring @prisma/client directly (happens under Vitest's CJS interop) gives the more direct error:

Error: Cannot find module '.prisma/client/default'
Require stack:
- node_modules/@prisma/client/default.js

Same root cause both times: no client was ever generated at the default location because output was customized. Node just surfaces it differently depending on the import path.

Repository URL example

None, the schema + two commands above is the whole reproduction.

OS

macOS 26.6.2

Node version

v22.18.0

Library version

@tsed/prisma 8.38.2, also confirmed on the latest 8.38.4 (transformScalarToType.js hasn't changed between the two).

Additional context

Unrelated to the requiresGenerators: ["prisma-client-js"] constraint (not supporting the new prisma-client generator yet). Hits regardless of generator, transformScalarToType.ts never checks which provider generated the client.

Custom output is Prisma's own default now for new projects (see their post on why they moved away from generating into node_modules), so this will probably come up more, not less.

Fix would probably be threading the same prismaClientPath that generateClientIndex.ts already resolves into TransformContext, so transformScalarToType.ts can use it too. Can help test a fix if that's useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions