t3-env icon indicating copy to clipboard operation
t3-env copied to clipboard

Ability to load environment variables at runtime, not build time

Open timheerwagen opened this issue 1 year ago • 9 comments

I wonder if it is possible to load the environment variables at runtime, as with "https://github.com/expatfile/next-runtime-env". This is not possible in the example with nextjs.

timheerwagen avatar Jun 13 '23 17:06 timheerwagen

Yeah, I assumed t3-env already did this! 🥲

It's important for self-hostable applications that are packaged into a docker image, end users should be able to edit the runtime env

Would you accept PR for this? I could try to implement a solution

baptisteArno avatar Aug 14 '23 08:08 baptisteArno

I think we can make t3-env compatible with next-runtime-env at least! I'll take a look.

baptisteArno avatar Aug 14 '23 08:08 baptisteArno

@baptisteArno I would be very happy if, if you find a solution, you share it here. I have been looking for something like this for some time. Thank you very much!

timheerwagen avatar Aug 14 '23 21:08 timheerwagen

This works:

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

const readVariable = (key) =>  {
  if(typeof window === 'undefined') return process.env[key]
  return window.__ENV[key]
}

export const env = createEnv({
  server: {
    DATABASE_URL: z.string().url(),
    OPEN_AI_API_KEY: z.string().min(1),
  },
  client: {
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
  },
  runtimeEnv: {
    DATABASE_URL: process.env.DATABASE_URL,
    OPEN_AI_API_KEY: process.env.OPEN_AI_API_KEY,
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY:
      readVariable(NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY),
  },
});

baptisteArno avatar Aug 15 '23 06:08 baptisteArno

Would you accept PR for this? I could try to implement a solution

Yes

juliusmarminge avatar Aug 16 '23 16:08 juliusmarminge

Would love to hear of any updates on this issue🤔

psycho-baller avatar Sep 26 '23 01:09 psycho-baller

In the project I'm working we adopted the t3-env lib with nextjs, to work around this validation problem in the build time I added an env var to skip the validation. Package.json

{ 
  "scripts": {
      "dev": "yarn generate && NODE_OPTIONS='--inspect' next dev",
      "build": "yarn generate && SKIP_ENV_VALIDATIONS='true' next build",
      "start": "next start",
    }
 }

env.mjs:

export const env = createEnv({
  isServer: typeof window === 'undefined' || process.env.NODE_ENV === 'test',
  /*
   * Serverside Environment variables, not available on the client.
   * Will throw if you access these variables on the client.
   */
  server: {
    
  },
  /*
 * Environment variables available on the client and server.
 *
 */
  shared: {
    NODE_ENV: z.enum(['test', 'development', 'production'])
      .optional()
      .default('production'),
    STAGE: z.enum(['local', 'dev', 'stg', 'prod']).default('prod'),
    APP_LOG_LEVEL: z
      .string()
      .optional()
      .default('info')
      .transform((data) => data.toLowerCase()),
  },
  /*
   * Environment variables available on the client.
   *
   * 💡 You'll get type errors if these are not prefixed with NEXT_PUBLIC_.
   */
  client: {
  },

  /*
   * Due to how Next.js bundles environment variables on Edge and Client,
   * we need to manually destructure them to make sure all are included in bundle.
   *
   * 💡 You'll get type errors if not all variables from `server` & `client` are included here.
   * All the env vars must end with the suffix _ENV to avoid a cycle import on the env-nextjs that enters in loop
   */
  runtimeEnv: {
    NODE_ENV: process.env.NODE_ENV,
    STAGE: process.env.STAGE,
    APP_LOG_LEVEL: process.env.APP_LOG_LEVEL,

  },
  skipValidation: process.env.SKIP_ENV_VALIDATIONS === 'true'
});

In this way I'm able to skip the validation for the build

rochaalexandre avatar Oct 05 '23 13:10 rochaalexandre

This works:

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

const readVariable = (key) =>  {
  if(typeof window === 'undefined') return process.env[key]
  return window.__ENV[key]
}

export const env = createEnv({
  server: {
    DATABASE_URL: z.string().url(),
    OPEN_AI_API_KEY: z.string().min(1),
  },
  client: {
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
  },
  runtimeEnv: {
    DATABASE_URL: process.env.DATABASE_URL,
    OPEN_AI_API_KEY: process.env.OPEN_AI_API_KEY,
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY:
      readVariable(NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY),
  },
});

I would like something like this, but for async functions. #146

SaadBazaz avatar Nov 10 '23 19:11 SaadBazaz

The correct way is what @rochaalexandre posted but SKIP_ENV_VALIDATION instead of SKIP_ENV_VALIDATIONS

SunnyAureliusRichard avatar Dec 09 '23 17:12 SunnyAureliusRichard