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

Next.js SSR mode - Environment Variables not being carried over to the created Lambda Functions #1987

Closed
4 tasks done
joelvarty opened this issue Jun 22, 2021 · 66 comments
Closed
4 tasks done
Labels
archived This issue has been locked. ssr Server Side Rendering feature

Comments

@joelvarty
Copy link

Before opening, please confirm:

App Id

d36aqre3ndgr2h

Region

us-east-1

Amplify Console feature

Environment variables

Describe the bug

When I set environment variables in the Amplify app, they are NOT being carried through to the Lambda functions that are automatically created for my Next.js SSR website.

Even if I set the environment variables later on the Lambda functions that are created, they get wiped out the next time I do a build.

Here's a link to my repo: https://github.com/agility/agilitycms-nextjs-ssr-starter

Expected behavior

I expected the environment variables to propagate from the Amplify settings to the Lambda functions that are created.

Reproduction steps

  • Create a new Next.js site on Amplify site using this repo: https://github.com/agility/agilitycms-nextjs-ssr-starter
  • Set the environment variables as needed (let me know if you need this information specifically)
  • Push a change to the main branch
  • The Environment variables are NOT on the Lambda functions.
  • The code in the Lambda functions that uses process.env.VARIABLE_NAME doesn't work

Build Settings

No response

Additional information

No response

@swaminator swaminator added the ssr Server Side Rendering feature label Jun 22, 2021
@haderman
Copy link

hey @joelvarty did you find any solution? I am having the same problem

@joelvarty
Copy link
Author

hey @joelvarty did you find any solution? I am having the same problem

Nope. I think this is an actual bug in the Next.js SSR Logic with Amplify

@Athena96
Copy link
Contributor

Hi, yes this is a bug and we are working on a fix. As a temporary workaround you can manually add the environment variable to your SSR Lambda function in the Lambda Console. Sorry you are facing this issue; we will follow up when this is fixed. Thanks!

@bajcmartinez
Copy link

@Athena96 thanks for the workaround, however, after a redeploy all lambda functions are published as a new version without the env. variables, is there a way to prevent that from happening?

On each push to my branches I'm losing the data and the app starts crashing.

Thanks

@aws-amplify aws-amplify deleted a comment from github-actions bot Jun 30, 2021
@joekendal
Copy link

Same issue here. The only solution I can think of in the meantime is to use secrets manager or ssm parameter store

@joekendal

This comment has been minimized.

@bajcmartinez
Copy link

Would be nice to have an ETA here, in the meanwhile I moved my config to parameter store as pointed out by @joekendal, however, it is not ideal as the parameter key name is "hardcoded" and it is not environment independent.

I can survive with it for now, but I can see this being a major issue for some others, it is very inconvinient.

@bajcmartinez
Copy link

Additionally, what would be the best way to give those lambda functions a policy to read from parameter store?

They have a custom role created by amplify, but there's no cloud formation template for it.

I did it manually for now

@joekendal
Copy link

@bajcmartinez yeah I haven't opted for that solution myself. Waiting for an update here. Will have to just deploy the API lambdas separately using CDK or something as opposed to Next.js /api/ route feature.

@bajcmartinez
Copy link

The problem is even more deep, even if I try to add the env variables manually I cannot deploy those functions as the CloudFront edge run environment does not support lambda environment variables as described here: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/edge-functions-restrictions.html#edge-function-restrictions-all

@joekendal
Copy link

The problem is even more deep, even if I try to add the env variables manually I cannot deploy those functions as the CloudFront edge run environment does not support lambda environment variables as described here: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/edge-functions-restrictions.html#edge-function-restrictions-all

I'm very confused then @Athena96 declares this is a bug and not a feature. But it seems it is in fact a feature and not a bug. Vercel uses Lambda@Edge and enables the user to provide environment variables. So they must be doing something during build time to make that available to process.env behind the scenes

@Nick-Navarro
Copy link

Hi @Athena96 has there been any movement on this?

@RealDrewKlayman
Copy link

This is a really big issue.

@ywroh
Copy link

ywroh commented Jul 22, 2021

Same issue here.

@Athena96
Copy link
Contributor

Hi all! We have added support for Environment variables for Next.js SSR apps. Follow these steps to enable:

  1. Add your desired environment variable in the Amplify Console like normal (steps)
  2. Update (or create) your next.config.js file with the environment variable you added in the Amplify Console. E.g if you created an environment variable named MY_ENV_VAR in the console in step 1) above, then you would add the following:
module.exports = {
  env: {
    MY_ENV_VAR: process.env.MY_ENV_VAR
  }
};
  1. Now after your next build you will be able to reference your environment variable (process.env.MY_ENV_VAR) in your SSR lambdas!

Thank you, and please let us know if you have any additional questions!

@bajcmartinez
Copy link

This is great news @Athena96, will try it today. Thanks so much, have a great weekend!

@bajcmartinez
Copy link

I was just thinking, nextjs has public and private env variables, some that get sent to the client start with NEXT_PUBLIC_, how are they treated now? will env. variables treated the same way? meaning non-public like SECRET_ENV_VAR, will that one remain for API and SSR ONLY?

@joelvarty
Copy link
Author

Hi all! We have added support for Environment variables for Next.js SSR apps. Follow these steps to enable:

  1. Add your desired environment variable in the Amplify Console like normal (steps)
  2. Update (or create) your next.config.js file with the environment variable you added in the Amplify Console. E.g if you created an environment variable named MY_ENV_VAR in the console in step 1) above, then you would add the following:
module.exports = {
  env: {
    MY_ENV_VAR: process.env.MY_ENV_VAR
  }
};
  1. Now after your next build you will be able to reference your environment variable (process.env.MY_ENV_VAR) in your SSR lambdas!

Thank you, and please let us know if you have any additional questions!

I appreciate this @Athena96! However... is there any reason not to simply create ALL the environment vars that are defined in Amplify on the Lambda functions? That way we don't need to have the extra config.

The reason this is important to us is that we build starter templates that run in a TON of cloud environments, and having to put vendor-specific config in there seems out of place.

@bajcmartinez
Copy link

@Athena96 I'm having issues now with my production build. It's not taking the env. overrides and always picking the default sets for the variables.

Could you please confirm this? Or is there anything else I should fix?

e.g.: In my app I have the following settings:
image

And it's always using the test...... URL

@Athena96
Copy link
Contributor

I was just thinking, nextjs has public and private env variables, some that get sent to the client start with NEXT_PUBLIC_, how are they treated now? will env. variables treated the same way? meaning non-public like SECRET_ENV_VAR, will that one remain for API and SSR ONLY?

Hi @bajcmartinez currently we do not make a distinction between the Next public/private env vars. They are all treated the same way.

@Athena96
Copy link
Contributor

@Athena96 I'm having issues now with my production build. It's not taking the env. overrides and always picking the default sets for the variables.

Could you please confirm this? Or is there anything else I should fix?

e.g.: In my app I have the following settings:
image

And it's always using the test...... URL

@bajcmartinez yes this is a bug and we are working on a fix. I will follow up when it is deployed.
As a workaround you can create separate env vars for the different values.

@Nick-Navarro
Copy link

Nick-Navarro commented Jul 29, 2021

@Athena96 I'm having issues now with my production build. It's not taking the env. overrides and always picking the default sets for the variables.
Could you please confirm this? Or is there anything else I should fix?
e.g.: In my app I have the following settings:
image
And it's always using the test...... URL

@bajcmartinez yes this is a bug and we are working on a fix. I will follow up when it is deployed.
As a workaround you can create separate env vars for the different values.

Hi @Athena96 I'm trying to follow your work around. I understand creating separate variables for different environments (e.g. API_URL_DEV vs API_URL_QA). My quesiton still stands at build time how would the application know which one to point to ? Is there a default variable from Amplify that can be used to know which ("env" or branch) is being built.

@Nick-Navarro
Copy link

@Athena96 I'm having issues now with my production build. It's not taking the env. overrides and always picking the default sets for the variables.
Could you please confirm this? Or is there anything else I should fix?
e.g.: In my app I have the following settings:
image
And it's always using the test...... URL

@bajcmartinez yes this is a bug and we are working on a fix. I will follow up when it is deployed.
As a workaround you can create separate env vars for the different values.

Hi @Athena96 I'm trying to follow your work around. I understand creating separate variables for different environments (e.g. API_URL_DEV vs API_URL_QA). My quesiton still stands at build time how would the application know which one to point to ? Is there a default variable from Amplify that can be used to know which ("env" or branch) is being built.

Hi All who are looking for a work around. AWS Amplify makes the branch you're building available in an envrionment variable (process.env.AWS_BRANCH). Using this env var I'm able to point to the correct url I want to use pending that branch build.

const baseURL = { develop: process.env.BASE_URL_DEV, qa: process.env.BASE_URL_QA, }[process.env.AWS_BRANCH || 'develop']

If there are other feature branches you can add them as options in the object, if a variable is not available for the AWS_BRANCH being built it will default to the develop option.

@drmzio
Copy link

drmzio commented Aug 5, 2021

Hi all! We have added support for Environment variables for Next.js SSR apps. Follow these steps to enable:

  1. Add your desired environment variable in the Amplify Console like normal (steps)
  2. Update (or create) your next.config.js file with the environment variable you added in the Amplify Console. E.g if you created an environment variable named MY_ENV_VAR in the console in step 1) above, then you would add the following:
module.exports = {
  env: {
    MY_ENV_VAR: process.env.MY_ENV_VAR
  }
};
  1. Now after your next build you will be able to reference your environment variable (process.env.MY_ENV_VAR) in your SSR lambdas!

Thank you, and please let us know if you have any additional questions!

This should probably be documented on the Amplify Docs here: https://docs.aws.amazon.com/amplify/latest/userguide/environment-variables.html#access-env-vars

@stefanoeb
Copy link

If someone else did all of the above and is hopeless as I was:

  1. Delete the app from amplify
  2. Create it again through the wizard (connect repo)
  3. Declare the environment variables on the wizard

My guess is there was some cache somewhere and my changes on the next.config.js were not getting picked up 🤷

@ferdingler
Copy link
Contributor

An alternative approach is to use .env files as described in the NextJS documentation https://nextjs.org/docs/basic-features/environment-variables. With this approach you don't need to specify the variables in your next.config.js file.

@multivoltage
Copy link

Instead I need ;)
I can use normal car on my backend code like getServerSideProps. To use env var in api files I need to use the trick with env object in config.
I cannot expose to browser variables like secrets ;).
This use cause is very bad. I hope aws will do something. A next Project with these corner case is very common in the real world

@traianturcu
Copy link

@Athena96 I'm having issues now with my production build. It's not taking the env. overrides and always picking the default sets for the variables.
Could you please confirm this? Or is there anything else I should fix?
e.g.: In my app I have the following settings:
image
And it's always using the test...... URL

@bajcmartinez yes this is a bug and we are working on a fix. I will follow up when it is deployed. As a workaround you can create separate env vars for the different values.

This bug is a pretty big deal - I can't see how we can use Amplify for CI/CD until this gets fixed..

@traianturcu
Copy link

There are 3-4 issues that stop us from using Amplify to deploy our Next.js app on Amplify:

  1. using the hack presented above to load the environment variables (by adding them to next.config.js) exposes them to the browser - so any env vars that are supposed to be secret and only available to the backend API functions are compromised

  2. variable override doesn't work making it impossible (or at least very inconvenient) to use Amplify for CI/CD

  3. similar to this issue, API routes return CloudFront 503 on versions beyond Next.js 12.0.8 - so at the moment we're stuck using version 12.0.8 in order to get the backend to work

  4. this is less important (and related to issues 1-2 above) - Amplify already has a nice dashboard for environment variables, and in my opinion that should be enough to configure everything, without any compromises or additional hacks required.

I really hope these will get fixed at some point in the near future, because that would make Amplify a truly great alternative to Vercel.

@multivoltage
Copy link

@traianturcu
For the first point, I tried a s small check. Putting variables on config do not expose any data to browser. I tried to search on Chrome console for the secret i put on config, and did not found.

@traianturcu
Copy link

@traianturcu For the first point, I tried a s small check. Putting variables on config do not expose any data to browser. I tried to search on Chrome console for the secret i put on config, and did not found.

When declaring two variables in env.local - one NEXT_PUBLIC_VAR1 and one VAR2, VAR2 is undefined in the frontend if you try to use it/output it/console.log it, and only the NEXT_PUBLIC_VAR1 is available. VAR2 is available only in the backend (for the pages/api handlers).
Unfortunately that is not the case when using the next.config.js hack offered as a solution above - all variables are defined in the frontend. So I don't think it's safe to have any secrets in the env vars when deploying to Amplify.

I'm not sure if this means the security of the app is compromised (e.g. secret keys being incorporated in the .js files being sent to the frontend), but at the very least by using the next.config.js hack we are losing some of the Next.js functionality around env vars.

@multivoltage
Copy link

multivoltage commented Feb 19, 2022

I did not undestand. I used AAA_VAR in next config. This var is available on files under /api. And searching on code I cannot find that secret on browser.
I used AAA_VAR_2 in .env (without next config) and my server side code (getStaticProps) read that var correctly.
I also check downloading artifact on awmplify. Searched on code with vscode. I found var only when used NEXT_PUBLIC prefix under /static/some_js_file.
Intead, searching for my secret (or name of secret var) you can see the var only in a file called required-server-files, and this filed fill var with secret because of the build on amplify

@traianturcu
Copy link

I did not undestand. I used AAA_VAR in next config. This var is available on files under /api. And searching on code I cannot find that secret on browser. I used AAA_VAR_2 in .env (without next config) and my server side code (getStaticProps) read that var correctly. I also check downloading artifact on awmplify. Searched on code with vscode. I found var only when used NEXT_PUBLIC prefix under /static/some_js_file. Intead, searching for my secret (or name of secret var) you can see the var only in a file called required-server-files, and this filed fill var with secret because of the build on amplify

I apologize for not explaining properly - I've recorded a very short video to show you the difference between Amplify vs. local/ Vercel /expected behavior - https://www.screencast.com/t/At4iOMAl

@multivoltage
Copy link

@traianturcu thank for video. That is what I understood after my experience (deploy next ssr without next export).

  • if you want a env var on browser put prefix NEXT_PUBLIC.
  • if you need access to process.env.VAR on backend code (getStaticPath, getServerSideProps,getStaticProps) you can define your var simply with VAR=xxx
  • if you need access to process.env.VAR inside /api/some-js-file you need to use the trick. But if you that VAR only in /api/.js files the js bundle (my bundle) did not contain that VAR.

Reading this: https://nextjs.org/docs/api-reference/next.config.js/environment-variables
Behavior expected is ok. Pass env in config expose var to js bundle.

Reading doc we can use aldo "phase" variables to know when use the trick or not. Probably we can use "PHASE_PRODUCTION_SERVER" only

@code-runner-2017
Copy link

yo guys, I think I found a solution. For me, the approach with next.config.js did not work, so after trying various things I saw AWS User Guide # Access Environment Variables and managed to get it working.

  1. I went to my Amplify app Build Settings
  2. I edited the App build specification amplify.yml file
  3. For every Environment Variable I had added in the Amplify app Environment Variables section, I added
    - echo "SOME_VARIABLE=$SOME_VARIABLE" >> .env
  4. That's it, after that I redeployed the build and I had all my variables present

@bojidaryovchev does this solution solve the problem of not exposing secret env vars to the browser?
Is it going to work as expected, i.e. only evn vars with NEXT_PUBLIC_... prefix are exposed to the browser?

@multivoltage
Copy link

@code-runner-2017 and... Is this valid solution in a case of normal build or only for next export build

@bojidaryovchev
Copy link

@code-runner-2017 @multivoltage not sure guys, you should test it out

@logan-jobzmall
Copy link

logan-jobzmall commented Jul 28, 2022

How is this still not fixed? @Athena96 ?

@alacret
Copy link

alacret commented Jul 29, 2022

I think the reason that it hasn't been fixed is that it is working as planned by the amplify console team.

In my case, the only way around this was to create the .env.local file using the build script, basically clearing and filling the file on every build.

It worked for a while but is not comfortable to support on multiple projects, so I just move away to Elastic Beanstalk

@shrikantshet
Copy link

Ticket open for over a year now!

@aktoriukas
Copy link

Is this been solved in any way? I can't believe that such a fundamental feature has bugs.

@quadroloop
Copy link

yo guys, I think I found a solution. For me, the approach with next.config.js did not work, so after trying various things I saw AWS User Guide # Access Environment Variables and managed to get it working.

  1. I went to my Amplify app Build Settings
  2. I edited the App build specification amplify.yml file
  3. For every Environment Variable I had added in the Amplify app Environment Variables section, I added
    - echo "SOME_VARIABLE=$SOME_VARIABLE" >> .env
  4. That's it, after that I redeployed the build and I had all my variables present

This worked for me! 👍

@aktoriukas
Copy link

aktoriukas commented Sep 28, 2022

adding:

commands:
        - API_URL=${API_URL}
        - ENV=${ENV}
        - npm run build

to amplify.yml solved the issue for me. But that seems more like a workaround than a solution.

@multivoltage
Copy link

Every guy with amplify seem to implement custom solution :)

@Majekdor
Copy link

adding:

commands:
        - API_URL=${API_URL}
        - ENV=${ENV}
        - npm run build

to amplify.yml solved the issue for me. But that seems more like a workaround than a solution.

This as well as adding the environment variables to the module exports worked for me!

@pbs-jmo
Copy link

pbs-jmo commented Oct 27, 2022

yo guys, I think I found a solution. For me, the approach with next.config.js did not work, so after trying various things I saw AWS User Guide # Access Environment Variables and managed to get it working.

  1. I went to my Amplify app Build Settings
  2. I edited the App build specification amplify.yml file
  3. For every Environment Variable I had added in the Amplify app Environment Variables section, I added
    - echo "SOME_VARIABLE=$SOME_VARIABLE" >> .env
  4. That's it, after that I redeployed the build and I had all my variables present

This worked for me! 👍

This worked for me -- BUT, only if I wrote to ./.env. Writing to .env did not work. Still scratching my head over that one.

@akskos
Copy link

akskos commented Oct 28, 2022

Hi all! We have added support for Environment variables for Next.js SSR apps. Follow these steps to enable:

1. Add your desired environment variable in the Amplify Console like normal ([steps](https://docs.aws.amazon.com/amplify/latest/userguide/environment-variables.html#setting-env-vars))

2. Update (or create) your `next.config.js` file with the environment variable you added in the Amplify Console. E.g if you created an environment variable named `MY_ENV_VAR` in the console in step 1) above, then you would add the following:
module.exports = {
  env: {
    MY_ENV_VAR: process.env.MY_ENV_VAR
  }
};
3. Now after your next build you will be able to reference your environment variable (`process.env.MY_ENV_VAR`) in your SSR lambdas!

Thank you, and please let us know if you have any additional questions!

Does not work for me. I see my env variables in the build phase if I log process.env, but not in the actual api code that executes in Lambda. I also tried the method of adding env vars to amplify.yml commands like @aktoriukas did but that didn't work either. Then I tried setting environment variables in the configuration of my lambda@edge and on depoloy it says "Environment variables are not supported"

@lancegliser
Copy link

lancegliser commented Nov 3, 2022

I was able to launch on Amplify today using the setup below. I do have a .env, but my configurations are in a created .env.local file for each unique deployment. A minor change to use dotenv-cli was required to hook the migrate, seed, etc scripts up to read it. The deployed lambdas worked with .env.local fine from the start.

amplify.yml

version: 1
frontend:
  phases:
    preBuild:
      commands:
        - touch .env.local
        - echo "DATABASE_URL=$DATABASE_URL" >> .env.local
        - yarn install
        - npx dotenv -e .env.local -- npx prisma generate
        - npx dotenv -e .env.local -- npx prisma db push
        - npx dotenv -e .env.local -- npx prisma db seed
    build:
      commands:
        - yarn run build
  artifacts:
    baseDirectory: .next
    files:
      - "**/*"
  cache:
    paths:
      - node_modules/**/*

package.json

{
  "name": "example",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start -p 80",
    "start:local": "next start",
    "lint": "next lint",
    "migrate": "dotenv -e .env.local -- npm run generate && npm run push && npm run seed",
    "generate": "npx prisma generate",
    "push": "dotenv -e .env.local -- npx prisma db push",
    "seed": "dotenv -e .env.local -- npx prisma db seed",
    "test": "npm run lint && jest --forceExit --detectOpenHandles"
  },
  "prisma": {
    "seed": "node prisma/seed.js"
  },
  "dependencies": {
    "@prisma/client": "^4.3.1",
    "@reduxjs/toolkit": "^1.8.5",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.3.2",
    "@testing-library/user-event": "^7.1.2",
    "next": "12.2.5",
    "next-redux-wrapper": "^7.0.5",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-hook-form": "^7.34.2",
    "react-redux": "^8.0.2"
  },
  "devDependencies": {
    "@types/jest": "^27.0.1",
    "@types/node": "18.7.14",
    "@types/react": "18.0.18",
    "@types/react-dom": "18.0.6",
    "@typescript-eslint/eslint-plugin": "^5.30.6",
    "autoprefixer": "^10.4.8",
    "dotenv": "^16.0.3",
    "dotenv-cli": "^6.0.0",
    "eslint": "^8.20.0",
    "eslint-config-next": "12.2.5",
    "husky": "^8.0.1",
    "jest": "^27.2.0",
    "lint-staged": "^13.0.3",
    "postcss": "^8.4.16",
    "prettier": "^2.7.1",
    "prettier-eslint": "^15.0.1",
    "prisma": "^4.3.1",
    "supertest": "^6.1.6",
    "tailwindcss": "^3.1.8",
    "ts-jest": "^27.1.4",
    "ts-node": "^10.8.1",
    "typescript": "4.8.2"
  }
}

next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
};

module.exports = nextConfig;

One thing that did bite me along the path was the Amplify default command:

- echo "DATABASE_URL=$DATABASE_URL" >> .env.local

My file started with a comment:

# Environment settings shared across all deployments

Output the results of the file after the Amplify echo command (cat .env) showed that the output had been append to my comment not a new line:

# Environment settings shared across all deploymentsDATABASE_URL=****

Thus my decision to flee and immediately swap to a .env.local brand new each time.

@calavera
Copy link
Contributor

I am pleased to share we have now launched support for Next.js 12 and 13. This new release solves this problem in our previous support, take a look at the documentation to learn how to add environment variables to the functions: https://docs.aws.amazon.com/amplify/latest/userguide/ssr-environment-variables.html

For more information about the launch, please see our blog post at https://aws.amazon.com/blogs/mobile/amplify-next-js-13

If you run into issues with Next.js 12 or 13, please open a new issue so we can track it specifically. Thank you everyone for your patience and support. It's much appreciated.

@github-actions
Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot added the archived This issue has been locked. label Nov 17, 2022
@github-actions github-actions bot locked and limited conversation to collaborators Nov 17, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
archived This issue has been locked. ssr Server Side Rendering feature
Projects
None yet
Development

No branches or pull requests