prisma: `ENOENT` with custom output and ESM module in NPM monorepo (including Nextjs): `no such file or directory, open /.../schema.prisma...`

Bug description

I’ve been seeing a slew of issues involving using Prisma-based local packages in an NPM monorepo with Nextjs, and I’ve encountered a case I could not solve using the existing solutions.

As a recap of the other issues, it seems when using a Prisma-based package (i.e. a package that ships with its own prisma.schema) in Nextjs, the resulting webpack bundles will look for schema.prisma relative to the directory of the bundle rather than the directory of the package dist. This results in errors like this:

Error: ENOENT: no such file or directory, open '/.../.next/cache/webpack/client-development/schema.prisma'

Now there have been some proposed solutions thus far, but the big difference is my package is an ESM package whereas the ones in the previous issues have been CJS packages. For example, one of the workarounds proposed here says to modify the Next config to use webpack externals and outputFileTracingRoot like so:

module.exports = {
  output: 'standalone',
  experimental: {
    outputFileTracingRoot: path.join(__dirname, '../../'),
  },
  webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
    config.externals = [...config.externals, '<PACKAGE>']

    return config
  },
}

However, if <PACKAGE> is an ESM module, this means webpack never transpiles it to CJS, resulting in a Error: require() of ES Module error when you try using the package in a Nextjs app. Hence, this fix does not work for ESM-based packages.

How to reproduce

I have created a repro repo here: https://github.com/slimshreydy/prisma-monorepo-esm-output-bug. See the README for instructions on local setup.

Expected behavior

Importing a package that uses prisma in Nextjs should look for the schema.prisma file in the package’s dist directory rather than the .next/ folder.

Prisma information

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

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  createdAt DateTime @default(now())
}
import { NextApiRequest, NextApiResponse } from "next";
import { prisma } from "@prisma-monorepo-esm-output-bug/package/dist";

export default async (req: NextApiRequest, res: NextApiResponse) =>
  res.json(await prisma.user.findMany());

Environment & setup

  • OS: macOS 10.15
  • Database: PlanetScale
  • Node.js version: v18.12.1

Prisma Version

prisma                  : 4.9.0
@prisma/client          : 4.9.0
Current platform        : darwin
Query Engine (Node-API) : libquery-engine ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5 (at ../node_modules/@prisma/engines/libquery_engine-darwin.dylib.node)
Migration Engine        : migration-engine-cli ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5 (at ../node_modules/@prisma/engines/migration-engine-darwin)
Introspection Engine    : introspection-core ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5 (at ../node_modules/@prisma/engines/introspection-engine-darwin)
Format Binary           : prisma-fmt ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5 (at ../node_modules/@prisma/engines/prisma-fmt-darwin)
Format Wasm             : @prisma/prisma-fmt-wasm 4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5
Default Engines Hash    : ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5
Studio                  : 0.479.0

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 3
  • Comments: 17 (6 by maintainers)

Commits related to this issue

Most upvoted comments

For those using multiple Prisma Clients, we are going to schedule follow-up work via https://github.com/prisma/prisma/issues/18069. Please upvote it if you need multi-client support, and don’t hesitate to share more information there.

@millsp, I’ve tried, and it doesn’t work. Using experimental-prisma-webpack-plugin and changes in Next.js config from the workaround you linked, I’m getting the error: Could not find mapping for model <model_name>

I have the same problem. Here’s the repo that reproduces the issue: https://github.com/adrianbienias/nextjs-prisma-monorepo-issue

I’ve added a workaround branch to the repo and explained it in the README.

Steps that worked for me as a temporary solution are quite simple:

  1. Set output in schema.prisma to shared monorepo node_modules
output = "../../node_modules/@prisma/client/<package_name>"
  1. Import Prisma clients from @prisma/client/<package_name>

Hey @slimshreydy thanks for the thorough issue description. We really appreciate the effort! I just tried your reproduction and I have a few remarks. Right now, your reproduction does not fail for me, as it seems you already enabled the workaround and found how to circumvent your ts/esm issue. Could you please provide a branch with the repro that matches your description?

I have seen this problem with TypeScript a few days ago so I am working on a better workaround. We are building a webpack plugin that will fix that for you. In short, this plugin ensures that the necessary files are correctly copied for you but does not conflict with your other settings. You can try it now via https://www.npmjs.com/package/experimental-prisma-webpack-plugin

const { PrismaPlugin } = require('experimental-prisma-webpack-plugin')

module.exports = {
  output: 'standalone',
  webpack: (config, { isServer }) => {
    if (isServer) {
      config.plugins = [...config.plugins, new PrismaPlugin()]
    }

    return config
  },
}

@Rafcin Packages in my repo aren’t separated in order to handle prisma. They are separated to represent a random package that uses its own schema.prisma.

T3 app should work well the same way.

In <monorepo-root>/t3-app/prisma/schema.prisma set for the client generator output = "../../node_modules/@prisma/client/t3-app"

and in db.ts set import { PrismaClient } from "@prisma/client/t3-app"

Also, remember to include t3-app in monorepo root package.json in workspaces, so it will use shared root node_modules.

Hi @millsp! Were you trying the app locally (using npm run dev -w web to start the server in dev mode), or did you deploy it to Vercel? On main, I was encountering issues with the former but the latter worked fine for me. Using the webpack externals workaround locally causes a “require of ESM module” error (presumably since webpack never ends up transpiling the module).

Regardless, I was able to add experimental-prisma-webpack-plugin to my Nextjs app and I am happy to report it works! Both the local and hosted versions of my nextjs work fine now. No more ENOENT errors! Thanks for your quick work here.

@janpio Tagging you since it seems you’ve been addressing most of these issues!