serverless-next.js icon indicating copy to clipboard operation
serverless-next.js copied to clipboard

Variables defined in .env are not overrideable by other .env files at build time

Open JamiesWhiteShirt opened this issue 4 years ago • 6 comments

Issue Summary

Environment variables defined in .env can normally be overridden by other conventional Next.js .env files such as .env.local, but they cannot be overridden when building with Serverless Next.js.

In our case, we attempted to override a value defined in .env by defining a different value in .env.local before deploying. When building manually with next build, overriding works as expected, but when when building with Serverless Next.js, it is not overridden.

This only applies at build time. Thus it may affect next.config.js and statically generated pages, which may be rendered with unexpected values for NEXT_PUBLIC_ or other statically defined environment variables. At runtime, the environment variables work as expected on the server.

Actual behavior

When deploying with Serverless Next.js, .env takes precedence over all other conventional Next.js .env files.

Expected behavior

.env should be overrideable by other conventional Next.js .env files. Next.js loads .env files with the following precedence:

  1. .env.${mode}.local
  2. .env.local
  3. .env.${mode}
  4. .env

A value in any of these files may be overridden by any file that precedes it. Thus, .env.local should be able to override values defined in .env.

Taken a step further, one might expect Serverless Next.js to load environment variables the same way Next.js does for use in configuring Serverless, but it is not essential.

Steps to reproduce

  1. Create a Next.js app with a statically optimizable page pages/index.jsx:
export default () => <p>{process.env.NEXT_PUBLIC_HELLO}</p>;
  1. Add .env and .env.local:
# .env
NEXT_PUBLIC_HELLO="Default hello"
# .env.local
NEXT_PUBLIC_HELLO="Overridden hello"
  1. Run next dev
  2. Observe that the index page says "Overridden hello".
  3. Deploy with Serverless Next.js.
  4. Observe that deployed page says "Default hello".

Screenshots/Code/Configuration/Logs

Versions

  • OS/Environment: Ubuntu 20.04.3 LTS (GitHub Actions), macOS Monterey 12.0.1
  • @sls-next/serverless-component version: 3.6.0
  • Next.js version: 11.1.2

Additional context

Next.js loads .env files by order of precedence (source). A value loaded from a .env file cannot be overwritten by a .env file that is loaded after, thus a .env file that is loaded before another can be said to override the other. This is because dotenv will not overwrite an environment variable that is already defined, which is by design.

The problem is that @serverless/cli automatically loads the .env file before Next.js gets a chance to load them in its own order. The child process calling next build inherits these environment variables, effectively resulting in the .env file loading before all the others, meaning its values cannot be overridden.

This is a trace to where .env is being loaded by @serverless/cli when calling serverless:

    at Object.config (node_modules/dotenv/lib/main.js:78:11)
    at CLI.setCredentials (node_modules/@serverless/cli/src/Context.js:101:24)
    at async CLI.init (node_modules/@serverless/cli/src/Context.js:72:5)
    at async Template.init (node_modules/@serverless/core/src/Component.js:68:5)
    at async Object.runComponents (node_modules/@serverless/cli/src/index.js:200:5)

This is understandably more of a @serverless/cli integration issue, but seeing as it is abandoned and you are maintaining patches for it, it might be something that could be solved by Serverless Next.js.

Checklist

  • [x] You have reviewed the README and FAQs, which answers several common questions.
  • [x] You have reviewed our DEBUGGING wiki and have tried your best to include complete information and reproduction steps (including your configuration) as is possible. As there is only one maintainer (who maintains this in his free time) and thus very limited resources, if you have time, please try to debug the issue a bit yourself if possible.
  • [x] You have first tried using the most recent latest or alpha @sls-next/serverless-component release version, which may have already fixed your issue or implemented the feature you are trying to use. Note that the old serverless-next.js component and the serverless-next.js plugin are deprecated and no longer maintained.

JamiesWhiteShirt avatar Dec 07 '21 16:12 JamiesWhiteShirt

I see that you mentioned Github Actions. Did you add .env.local to your .gitignore? If that is the case .env.local does not exist when running Github Actions. Just making sure.

albehrens avatar Dec 24 '21 05:12 albehrens

Good guess, but it's not the case here. We do gitignore .env.local per convention, but our workflows are configured to install a .env.local file before running deployment to set staging-specific and production-specific environment variables.

JamiesWhiteShirt avatar Dec 24 '21 12:12 JamiesWhiteShirt

I am not here to tell you how you should do your work, but creating a .env.local for injecting environment variables (I guess for not committing secrets to your repository) as part of your CI/CD pipeline seems like a hack to me. I ran into the same challenge however when setting up my pipeline. This comment solved my problems: https://github.com/serverless-nextjs/serverless-next.js/issues/184#issuecomment-719137988

albehrens avatar Dec 25 '21 13:12 albehrens

I am not here to tell you how you should do your work, but creating a .env.local for injecting environment variables (I guess for not committing secrets to your repository) as part of your CI/CD pipeline seems like a hack to me. I ran into the same challenge however when setting up my pipeline. This comment solved my problems: #184 (comment)

We opted not to do that due to the first tradeoff listed in the same comment. Using .env files we can instead explicitly opt in via NEXT_PUBLIC_ prefix.

JamiesWhiteShirt avatar Dec 25 '21 14:12 JamiesWhiteShirt

yarn run v1.22.10
$ next dev -p 6626
Browserslist: caniuse-lite is outdated. Please run:
npx browserslist@latest --update-db
Loaded env from /Users/user/Documents/Apps/grida/designto-code/editor/.env.local
Loaded env from /Users/user/Documents/Apps/grida/designto-code/editor/.env

See that .env is overriding .env.local. The order should be

  1. .env.local
  2. .env

Using NextJS 10.0.3

softmarshmallow avatar Jan 03 '22 07:01 softmarshmallow

We are in August 2023 and it's even worse in case of output mode.

Steps to reproduce:

  1. Set PORT=3333 in your .env.production
  2. Build the app
  3. Run the server.js with a different inlined port: PORT=3000 node .next/output/server.js
  4. In one of your server components, console.log(process.env.PORT) and cry when you see "3333"

Vercel, could we please drill the process.env variables into the app and pages workers???

Silverium avatar Aug 17 '23 06:08 Silverium