Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@prisma/client magically loading .env file (and mutating process.env in the process) #15620

Open
cyrilchapon opened this issue Sep 30, 2022 · 11 comments
Labels
kind/improvement An improvement to existing feature and code. team/client Issue for team Client. topic: breaking change topic: env topic: .env

Comments

@cyrilchapon
Copy link

Bug description

On a fresh repository with just prisma and @prisma/client installed, the fact of importing @prisma/client silently loads my local .env file without letting me any chance to disable this behavior.

The variety of use-cases (#12535, #10104 and more generally the amount of dotenv-related issues ) appear to me as a signal that prisma is apparently trying to do too much when loading such a file.

My personal use-case is simple; I want to strongly validate environment format (with envalid or even zod) BEFORE doing anything else. I also want to provide my own configuration to my "providers" (and prisma is one of them) in the parsed format I want; without mutating process.env .

Put simply :

import { config } = './config'
const appEnv = config.getEnv() // checked

const myProvider = new MyProvider(appEnv.someKey)

I saw several strategies (docs/environment-variables, docs/using-multiple-env-files, docs/managing-env-files-and-setting-variables), and various possibilities through issues (like "use dotenv-cli before calling prisma, prisma and dotenv will be clever enough to detect you already loaded env"). Those are simply not enough for me and this use case. I want to entirely disable dotenv, not only for development but even more for production.

How to reproduce

Install a fresh repository, and add @prisma/client + prisma.
Create a sample schema, and prisma generate

.env

FOO=bar

01-nothing.ts

console.log(process.env)
// undefined

02-importing-prisma.ts

import '@prisma/client'
console.log(process.env)
// bar

Expected behavior

I'd expect @prisma/client not parsing anything like a .env unless I tell it to do so.
Alternatively, I'd expect @prisma/client to accept me telling "don't load it, please".

In other words : the default of loading .env appears legit; but

  • If one can disable it
  • In consequence, if it's done in the constructor invocation instead of the module import

Prisma information

Irrelevant for this issue

Environment & setup

  • OS: macOS
  • Database: PostgreSQL
  • Node.js version: v18.8.0

Prisma Version

prisma                  : 4.4.0
@prisma/client          : 4.4.0
Current platform        : darwin
Query Engine (Node-API) : libquery-engine f352a33b70356f46311da8b00d83386dd9f145d6 (at node_modules/@prisma/engines/libquery_engine-darwin.dylib.node)
Migration Engine        : migration-engine-cli f352a33b70356f46311da8b00d83386dd9f145d6 (at node_modules/@prisma/engines/migration-engine-darwin)
Introspection Engine    : introspection-core f352a33b70356f46311da8b00d83386dd9f145d6 (at node_modules/@prisma/engines/introspection-engine-darwin)
Format Binary           : prisma-fmt f352a33b70356f46311da8b00d83386dd9f145d6 (at node_modules/@prisma/engines/prisma-fmt-darwin)
Format Wasm             : @prisma/prisma-fmt-wasm 4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6
Default Engines Hash    : f352a33b70356f46311da8b00d83386dd9f145d6
Studio                  : 0.474.0
Preview Features        : interactiveTransactions
@cyrilchapon cyrilchapon added the kind/bug A reported bug. label Sep 30, 2022
@millsp millsp added team/client Issue for team Client. bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. topic: env topic: .env labels Oct 4, 2022
@hendrikbursian
Copy link

hendrikbursian commented Oct 13, 2022

I agree with cyrilchapon here. The behavior should be optional. And it shouldn't be a side effect of simply importing the @prisma/client module without instantiating the client.

I had several occasions now where the silent loading of environment variables by only importing the @prisma/client module led to confusing behavior which was hard to track down.

One while writing tests (with custom environment variables) where the @prisma/client was imported behind a series of modules.
Another one similar to the authors description while providing a loading and validation mechanism for our application config.

It would be great to be able to disable the automatic loading of the .env files.

@utkuturunc
Copy link

for the time being i am working around this by loading the .env first, then importing prisma using await import()

@Mydayyy
Copy link

Mydayyy commented Feb 17, 2023

I had several occasions now where the silent loading of environment variables by only importing the @prisma/client module led to confusing behavior which was hard to track down.

Just spent an hour trying to find out why my env variables were messed up. Prisma is clashing with nestJS here and I prefer to handle loading the env variables myself using nestjs. We really need to be able to turn this off

@janpio
Copy link
Member

janpio commented Feb 17, 2023

In which context exactly did this mess with nestJS, Prisma Client in a NestJS app? How did the clash happen?

An issue with a concrete request for an env var to disable the behavior might be a good idea then.

@Mydayyy
Copy link

Mydayyy commented Feb 18, 2023

Hi!

My concrete issue was:

  • I told NestJS to load the variables in the following order: .env.local and .env after
  • The first variable which NestJS finds is supposed to take effect, so .env.local should override .env
  • Since prisma automatically loads the variables during the import from .env, the variables from inside .env.local already existed when NestJS tried parsing .env.local, so those did not take precedence but were ignored by NestJS

I can do additional testing on this next week and provide a minimal reproducible example together with a concrete issue/feature request.

@cyrilchapon
Copy link
Author

To expand on use-cases, and to get rid of any .env-related misperception, basic user story :

in production, I want to run a yarn start (different from yarn dev) which DOES NOT load any .env at all.

There are several use-cases where a .env is not relevant at all, including deploying on Vercel, developing in a containerized Node.js env, deploying on Heroku.

I know : one should exclude its .env from got sources; and after-all dotenv keep actual environment variables precedence over .env files. But the fact is, in my opinion, that's not a viable reason to "try and load them anyway".

Let's please keep in mind that at the root of the thoughts about "environment variables configuration" there is 12 factors; which is not about .env files at all.

@janpio janpio changed the title @prisma/client magically loading .env file (and mutating process.env in the process) @prisma/client magically loading .env file (and mutating process.env in the process) May 26, 2023
@Mydayyy
Copy link

Mydayyy commented Jul 23, 2023

You can find a minimal repro repo here: https://github.com/Mydayyy/nestjs-prisma-bug-repro

The readme hopefully should cover the usage.

Also there is already a related issue here: #18239

@janpio
Copy link
Member

janpio commented Jul 24, 2023

Ok, so it is correct that your NestJS app is conflicting with Prisma's behavior because NestJS loads environment variables from certain files in a certain order, which Prisma then messes with by its normal, defined behavior?

@janpio janpio added kind/improvement An improvement to existing feature and code. and removed bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. kind/bug A reported bug. labels Jul 24, 2023
@saramorillon
Copy link

saramorillon commented Aug 11, 2023

My use case is the following: I have a .env in my local environnement to provide envrionment variables while developing. I also have a .env.test file used when I run unit tests and explicitely loaded with dotenv.
When I run my tests, I don't want the .env to be loaded, I want to load only the .env.test file.

I found this workaround which seems to do the trick: in my tests setup file, I mock the package @prisma/internals (which contains the tryLoadEnvs function). With that, my .env file is not loaded anymore during my tests.

vi.mock('@prisma/internals')

Is it a good practice? Is there any downside I'm not aware of?

@fgroenendijk
Copy link

The case I have is a prisma client in /apps/core which is reading the .env from /apps/core. This combined with another app in /apps/anotherApp. I have two variables in both /apps/core/.env and /apps/anotherApp/.env which are named the same. EXAMPLE="first_example" in /apps/core/.env and EXAMPLE="second_example" in /apps/anotherApp/.env.
In this case anotherApp shows "first_example" where it should show "second_example".

To fix this:

  • move the /apps/core/.env file to /apps/core/environment/.env
  • change the app.module.ts in /apps/core to include:
    @Module({ imports: [ ... ConfigModule.forRoot({ isGlobal: true, envFilePath: 'environment/.env', }), ... })

So now the prisma client can still have a .env file in /apps/core but the EXAMPLE variable is moved to /apps/core/environment/.env

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/improvement An improvement to existing feature and code. team/client Issue for team Client. topic: breaking change topic: env topic: .env
Projects
None yet
Development

No branches or pull requests

8 participants