t3-oss / t3-env

https://env.t3.gg
MIT License
2.67k stars 86 forks source link

Can't use env in drizzle.config.ts file #180

Closed F2BEAR closed 7 months ago

F2BEAR commented 8 months ago

I'm working on a simple app to try something where I got drizzle and drizzle-kit installed, it's a next-js v14.x with @t3-oss/env-nextjs v0.8.0.

I'm trying to run drizzle-kit generate:pg but I got the following error: ❌ Invalid environment variables: { DATABASE_URL: [ 'Required' ] }

The weird thing is that this only happens when I run the drizzle-kit command but I have a .env.local file and when I run pnpm dev the dev server initializes with no error as expected.

Here is my env.mjs file:

import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";

export const env = createEnv({
  server: {
    DATABASE_URL: z.string(),
  },
  runtimeEnv: {
    DATABASE_URL: process.env.DATABASE_URL,
  },
});

And my drizzle.config.ts file:

import type { Config } from "drizzle-kit";
import { env } from "./src/server/env.mjs";

export default {
  schema: "./src/server/schemas",
  out: "./migrations",
  driver: "pg",
  dbCredentials: {
    connectionString: env.DATABASE_URL,
  },
} satisfies Config;

I know I can do connectionString: process.env.DATABASE_URL ?? "" and it would work good as I have the .env.local file with my env variable setted up but I think it would be better if I could use the exported env that I had already setted up for the rest of the app.

Thanks!

EDIT: I needed to add dotenv to read the value of process.env.DATABASE_URL in the drizzle config file so it was worse than what I expected as I needed to install 2 different libraries (this one and dotenv) to handle my env variables.

chungweileong94 commented 8 months ago

I needed to add dotenv to read the value of process.env.DATABASE_URL in the drizzle config file so it was worse than what I expected as I needed to install 2 different libraries (this one and dotenv) to handle my env variables.

Yes, it's intentional. As t3-env is just an env validator instead of env loader.

deadcoder0904 commented 7 months ago

any solutions for this as i use drizzle too?

and just started using t3-env as well.

maybe should ask drizzle guys to support environment variables in someway?

juliusmarminge commented 7 months ago

what drizzle-kit version? drizzle loads env variable in later versions (cant remember in which they started)

deadcoder0904 commented 7 months ago

i'm using "drizzle-kit": "^0.20.14" but it supports process.env. im not sure if it does t3-env which is what i was asking?

do i need to use this code-block inside drizzle.config.ts for env.DATABASE_PATH to work?

import jiti from "jiti"
import { fileURLToPath } from "node:url"

const filename = fileURLToPath(import.meta.url)
const envPath = "./src/app/lib/env"

jiti(filename)(envPath)
juliusmarminge commented 7 months ago

im not sure what that code is supposed to do, but no you shouldn't need to do anything special. just import the env object and use it in the drizzle config. drizzle will load the variables onto process.env and assuming you have set the runtime env appropriately (as the OP's env file) it will work

deadcoder0904 commented 7 months ago

i don't think drizzle-kit actually loads environment variables. i've tested.

you have to import dotenv.config() for process.env to work.

only next.js does load process.env automatically.

i use 2 other commands: drizzle-kit & tsx & in both of them, i have to manually load environment variables using either dotenv at the top of the file or with tsx i do node --import tsx --env-file .env.development ./src/scripts/drizzle-migrate.ts.

juliusmarminge commented 7 months ago

it definetely loads envs: CleanShot 2024-02-08 at 10 52 28@2x

https://github.com/juliusmarminge/drizzle-env


tsx might not load so for that you'd probably need to run your command right there or use bun or something else that loads it for you

deadcoder0904 commented 7 months ago

no, you are using bun. bun loads .env by default i think.

deadcoder0904 commented 7 months ago

oh you said the same below. didn't read it haha.

i'm on windows where bun will come in a week but it doesn't work with drizzle yet. bun repo has some drizzle issues. besides i think it'll still need 6 months to be usable so will stick to pnpm & tsx for now.

juliusmarminge commented 7 months ago

CleanShot 2024-02-08 at 10 54 49@2x

here is the same run but with pnpm - drizzle loads envs. please reopen with a reproduction for a case where it doesn't work

deadcoder0904 commented 7 months ago

can you paste your drizzle.config.ts?

i just tried with this:

// import * as dotenv from "dotenv"
import type { Config } from "drizzle-kit"

// bug in drizzle: see https://github.com/drizzle-team/drizzle-orm/issues/1228
import { env } from "@/app/lib/env"

// dotenv.config({ path: ".env.development" })

export default {
    schema: "./src/app/db/schema.ts",
    out: "./src/app/db/migrations",
    driver: "better-sqlite",
    dbCredentials: {
        url: env.DATABASE_PATH,
    },
    verbose: true,
} satisfies Config

and it didn't work.

but if i comment env & uncomment dotenv code & use process.env.DATABASE_PATH, then it works.

i even tried import { env } from "./src/app/lib/env" but that doesn't work either.

deadcoder0904 commented 7 months ago

i got this error:

❌ Invalid environment variables: {
  NODE_ENV: [ 'Required' ],
  NGROK_URL: [ 'Required' ],
}

E:\example-proj\node_modules\.pnpm\@t3-oss+env-core@0.9.2_typescript@5.3.3_zod@3.22.4\node_modules\@t3-oss\env-core\dist\index.js:29
        throw new Error("Invalid environment variables");
              ^

Error: Invalid environment variables
    at onValidationError (E:\example-proj\node_modules\.pnpm\@t3-oss+env-core@0.9.2_typescript@5.3.3_zod@3.22.4\node_modules\@t3-oss\env-core\dist\index.js:29:15)
    at createEnv (E:\example-proj\node_modules\.pnpm\@t3-oss+env-core@0.9.2_typescript@5.3.3_zod@3.22.4\node_modules\@t3-oss\env-core\dist\index.js:35:16)
    at createEnv (E:\example-proj\node_modules\.pnpm\@t3-oss+env-nextjs@0.9.2_typescript@5.3.3_zod@3.22.4\node_modules\@t3-oss\env-nextjs\dist\index.js:12:12)
    at Object.<anonymous> (E:\example-proj\src\app\lib\env.ts:5:20)
    at Module._compile (node:internal/modules/cjs/loader:1376:14)
    at Module._compile (E:\example-proj\node_modules\.pnpm\drizzle-kit@0.20.14\node_modules\drizzle-kit\bin.cjs:8644:30)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Object.newLoader [as .ts] (E:\example-proj\node_modules\.pnpm\drizzle-kit@0.20.14\node_modules\drizzle-kit\bin.cjs:8648:13)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)

Node.js v20.10.0
 ELIFECYCLE  Command failed with exit code 1.
juliusmarminge commented 7 months ago

please post a reproduction repo. i linked the one i tested on above https://github.com/t3-oss/t3-env/issues/180#issuecomment-1933716495

deadcoder0904 commented 7 months ago

annoying bug, i made a repro mimicking yours & it worked.

need to find the issue then.

F2BEAR commented 7 months ago

Hey @juliusmarminge, as for what version of drizzle-kit I'm using its 0.20.13.

I didn't try your repo yet as Im not at home right now but if it's a project that only has drizzle-kit and t3-env and it does work, what Im facing may be more of a problem while combining this two things with next js.

deadcoder0904 commented 7 months ago

@F2BEAR i made a new repro using next.js & its working in that project just fine.

not working in my main project though.

see for yourself -> https://github.com/deadcoder0904/drizzle-t3-oss-env

F2BEAR commented 7 months ago

Interesting, it's really similar to what I did but you're using the experimental__runtimeEnv without params instead of the runtimeEnv with process.env params inside of it as what the docs suggests.

I also have a similar small repo where I needed to use dotenv in the drizzle.config.ts file as the env vars from the env.mjs returned undefined only on that file and not in the nextjs 14.x app.

https://github.com/F2BEAR/conform-test

deadcoder0904 commented 7 months ago

experimental__runtimeEnv is used because its next.js > 13.something which is said in the docs itself so i don't have to repeat the client env variables again.

this is definitely a weird bug.

F2BEAR commented 7 months ago

And the first time you encountered this error where you using next.js v13.x or 14.x? Because I was working on 14.x and would like to know if it may be due to the next.js version or not

deadcoder0904 commented 7 months ago

i started using t3-env recently only. like 2 days ago. so next v14 was already released & i always use latest dependencies.

funny thing is right now i started my vscode after a full-nights sleep & saw that env. does autocomplete in typescript if i use ^0.9.1 but it gives red-squiggly lines in ^0.9.2.

but even if typescript autocomplete works, i still get an error when i run the script:

Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in E:\example.com\node_modules\@t3-oss\env-nextjs\package.json

juliusmarminge commented 7 months ago

0.9 was a breaking change and the package now only supports ESM so you need a module resolution that supports that

@deadcoder0904 I dont mean to sound rude but i need reproduction repos to be able to help, it's imoossible to sit and guess

juliusmarminge commented 7 months ago

the deadcoder0904/drizzle-t3-oss-env repo works fine for me. if that's the repo causing you issue, you mind sharing some more environment info (OS, Node version, pnpm version etc etc) and a screen recording maybe?

CleanShot 2024-02-09 at 08 43 37@2x

deadcoder0904 commented 7 months ago

@juliusmarminge you are not rude. i read some of my words again & it can be confusing. lets make it clear.

my drizzle-t3-env repo is what i was making as a reproduction in next.js modeled after your repro.

but it worked without errors.

it didn't work in my main private project.

but your Bundler solution worked in my main private project

so i guess the issues are all solved.

i'll still test all the scripts once & for all.

if it bugs, i'll comment or open a new issue.

otherwise assume its working fine now.

thanks for your help.

F2BEAR commented 7 months ago

@juliusmarminge did you have any chance with trying mine? I do have the error and the repo is a very small app with two functions.

I do anyways get the chance to do a workaround so it's not a critical thing, but it got me thinking. Thus why I opened this issue, in order to chat about it an know a bit better the caveats when combining this techs to do it better in the future

juliusmarminge commented 7 months ago

What's the issue? Seems to work fine?

CleanShot 2024-02-09 at 14 15 02@2x

F2BEAR commented 7 months ago

Ok so that's the reproduction of my code; it doesn't work in my computer returning the env vars as undefined so perhaps it may be due to my os?? That's the only thing I can imagine. I'm using windows 10 with git-bash

deadcoder0904 commented 7 months ago

i'm also on windows 11 with powershell 7 inside windows terminal.

in another project now that is a clone of my working repro again with a few added dependencies & still face an error. i also use bundler now.

@juliusmarminge see new reproduction which is simply a clone of my drizzle-t3-env repo -> https://github.com/deadcoder0904/easypanel-nextjs-sqlite

the error:

PS E:\easypanel-nextjs-sqlite> pnpm db:generate

> drizzle-t3-oss-env@0.1.0 db:generate E:\easypanel-nextjs-sqlite
> drizzle-kit generate:sqlite --config drizzle.config.ts

drizzle-kit: v0.20.14
drizzle-orm: v0.29.3

Reading config file 'E:\easypanel-nextjs-sqlite\drizzle.config.ts'
❌ Invalid environment variables: { DATABASE_URL: [ 'Required' ] }
E:\easypanel-nextjs-sqlite\node_modules\.pnpm\@t3-oss+env-core@0.9.2_typescript@5.3.3_zod@3.22.4\node_modules\@t3-oss\env-core\dist\index.js:29
        throw new Error("Invalid environment variables");
              ^

Error: Invalid environment variables
    at onValidationError (E:\easypanel-nextjs-sqlite\node_modules\.pnpm\@t3-oss+env-core@0.9.2_typescript@5.3.3_zod@3.22.4\node_modules\@t3-oss\env-core\dist\index.js:29:15)
    at createEnv (E:\easypanel-nextjs-sqlite\node_modules\.pnpm\@t3-oss+env-core@0.9.2_typescript@5.3.3_zod@3.22.4\node_modules\@t3-oss\env-core\dist\index.js:35:16)
    at createEnv (E:\easypanel-nextjs-sqlite\node_modules\.pnpm\@t3-oss+env-nextjs@0.9.2_typescript@5.3.3_zod@3.22.4\node_modules\@t3-oss\env-nextjs\dist\index.js:12:12)
    at Object.<anonymous> (E:\easypanel-nextjs-sqlite\src\app\lib\env.ts:5:20)
    at Module._compile (node:internal/modules/cjs/loader:1376:14)
    at Module._compile (E:\easypanel-nextjs-sqlite\node_modules\.pnpm\drizzle-kit@0.20.14\node_modules\drizzle-kit\bin.cjs:8644:30)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Object.newLoader [as .ts] (E:\easypanel-nextjs-sqlite\node_modules\.pnpm\drizzle-kit@0.20.14\node_modules\drizzle-kit\bin.cjs:8648:13)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)

Node.js v20.10.0
 ELIFECYCLE  Command failed with exit code 1.
deadcoder0904 commented 7 months ago

@juliusmarminge did you check my above reproduction? this one is new. i used bundler & it still didn't get rid of the error.

deadcoder0904 commented 7 months ago

@juliusmarminge @F2BEAR i think i found the issue. the issue is on jiti as it doesn't support type aliases -> https://github.com/unjs/jiti/issues/166

and i use type aliases @/app in every project rather than using ../app as its much cleaner.

if that gets fixed, i guess all these issues will be gone. i faced the same with knip and the author told me to look into jiti & i found that issue.

juliusmarminge commented 7 months ago

That doesnt explain why you wouldnt be able to load it in drizzle config though

deadcoder0904 commented 7 months ago

maybe, drizzle-kit uses something like jiti underhood.

but you are probably right.

rajdeep-ghosh commented 2 months ago

from what i have noticed drizzle only loads .env and not any other env files like .env.local or .env.development

bdrtsky commented 1 month ago

@rajdeep-ghosh holy crap, it is working with .env indeed and does not with .env.local. What the actual hell, Drizzle?

juliusmarminge commented 1 month ago

That's right. I reported to the drizzle team a while back that they should load more than just .env but that has not been added yet.

This has nothing to do with this library. We don't load anything, just validate what you put in runtimeEnv matches your defined schema.


I have the same issue, and honestly, I think this whole package is low quality, sorry

@bdrtsky do some research before slandering an open source package. It's completely your choice to use it, and if you don't like it just uninstall and move on...

bdrtsky commented 1 month ago

@juliusmarminge 🤡 talk to your mom like that

carterbancroft commented 1 month ago

This mostly hung me up when trying to run migrations in different environments (I have a unit test only DB for some integration tests).

I'm getting around it by doing... $env $(cat .test.env) npm run dzmigrate

Where dzmigrate is... $ drizzle-kit migrate --config=./path/to/drizzle.config.ts

jacobtipp commented 1 month ago

For anyone that may come across this error trying to run migrations from the command line.

Try loading env config with @next/env before createEnv

Like so:

import { createEnv } from '@t3-oss/env-core';
import { z } from 'zod';
import { loadEnvConfig } from '@next/env';

const projectDir = process.cwd();
loadEnvConfig(projectDir);

const config = createEnv({
  server: {
    POSTGRES_USER: z.string().min(1),
    POSTGRES_PASSWORD: z.string().min(1),
    POSTGRES_DB: z.string().min(1),
    POSTGRES_HOST: z.string().min(1),
    POSTGRES_PORT: z.string().min(4),
    RESEND_API_KEY: z.string().min(1),
    EMAIL_FROM: z.string(),
    APP_NAME: z.string().min(1),
    APP_HOST: z.string().min(1),
    APP_ENV: z.string().min(1),
  },
  runtimeEnv: {
    POSTGRES_USER: process.env.POSTGRES_USER,
    POSTGRES_PASSWORD: process.env.POSTGRES_PASSWORD,
    POSTGRES_DB: process.env.POSTGRES_DB,
    POSTGRES_HOST: process.env.POSTGRES_HOST,
    POSTGRES_PORT: process.env.POSTGRES_PORT,
    RESEND_API_KEY: process.env.RESEND_API_KEY,
    EMAIL_FROM: process.env.EMAIL_FROM,
    APP_NAME: process.env.APP_NAME,
    APP_HOST: process.env.APP_HOST,
    APP_ENV: process.env.APP_ENV,
  },
});

export default config;
brunodasilvalenga commented 4 weeks ago

For anyone that may come across this error trying to run migrations from the command line.

Try loading env config with @next/env before createEnv

Like so:

import { createEnv } from '@t3-oss/env-core';
import { z } from 'zod';
import { loadEnvConfig } from '@next/env';

const projectDir = process.cwd();
loadEnvConfig(projectDir);

const config = createEnv({
  server: {
    POSTGRES_USER: z.string().min(1),
    POSTGRES_PASSWORD: z.string().min(1),
    POSTGRES_DB: z.string().min(1),
    POSTGRES_HOST: z.string().min(1),
    POSTGRES_PORT: z.string().min(4),
    RESEND_API_KEY: z.string().min(1),
    EMAIL_FROM: z.string(),
    APP_NAME: z.string().min(1),
    APP_HOST: z.string().min(1),
    APP_ENV: z.string().min(1),
  },
  runtimeEnv: {
    POSTGRES_USER: process.env.POSTGRES_USER,
    POSTGRES_PASSWORD: process.env.POSTGRES_PASSWORD,
    POSTGRES_DB: process.env.POSTGRES_DB,
    POSTGRES_HOST: process.env.POSTGRES_HOST,
    POSTGRES_PORT: process.env.POSTGRES_PORT,
    RESEND_API_KEY: process.env.RESEND_API_KEY,
    EMAIL_FROM: process.env.EMAIL_FROM,
    APP_NAME: process.env.APP_NAME,
    APP_HOST: process.env.APP_HOST,
    APP_ENV: process.env.APP_ENV,
  },
});

export default config;

This worked for me! Just got an error:

import { loadEnvConfig } from '@next/env'
         ^^^^^^^^^^^^^
SyntaxError: Named export 'loadEnvConfig' not found. The requested module '@next/env' 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 '@next/env';
const { loadEnvConfig } = pkg;

but using on this way works fined:

import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";

import pkg from '@next/env';
const { loadEnvConfig } = pkg;

const projectDir = process.cwd()
loadEnvConfig(projectDir)