amplify-hosting icon indicating copy to clipboard operation
amplify-hosting copied to clipboard

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

Open joelvarty opened this issue 4 years ago • 55 comments

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

joelvarty avatar Jun 22 '21 16:06 joelvarty

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

haderman avatar Jun 28 '21 18:06 haderman

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

joelvarty avatar Jun 28 '21 18:06 joelvarty

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!

Athena96 avatar Jun 30 '21 17:06 Athena96

@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

jcmartinezdev avatar Jun 30 '21 21:06 jcmartinezdev

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

joekendal avatar Jun 30 '21 21:06 joekendal

@bajcmartinez You could try this in the meantime:

Go to AWS Console->Systems Manager->Parameter store

Create your environment variables. If you have different stages, you should be using different accounts anyway so the keys shouldn't clash

import AWS from 'aws-sdk'

var ssm = new AWS.SSM()

export default async (req: NextApiRequest, res: NextApiResponse) => {
    var MY_TABLE;

    ssm.getParamter({ Name: 'MY_TABLE' }, (err, data) => {
        MY_TABLE = data.Parameter?.Value!
    })

    ...
}

While not an ideal solution, it is perhaps futureproofed if you needed to reuse environment variables across different apps. Although the Amplify team will fix this in a few hours I hope. Perhaps best not to refactor large parts of code if it is to be fixed tomorrow or something.

joekendal avatar Jun 30 '21 21:06 joekendal

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.

jcmartinezdev avatar Jul 05 '21 09:07 jcmartinezdev

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

jcmartinezdev avatar Jul 05 '21 14:07 jcmartinezdev

@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.

joekendal avatar Jul 05 '21 15:07 joekendal

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

jcmartinezdev avatar Jul 06 '21 12:07 jcmartinezdev

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

joekendal avatar Jul 06 '21 17:07 joekendal

Hi @Athena96 has there been any movement on this?

Nick-Navarro avatar Jul 16 '21 14:07 Nick-Navarro

This is a really big issue.

RealDrewKlayman avatar Jul 21 '21 22:07 RealDrewKlayman

Same issue here.

ywroh avatar Jul 22 '21 07:07 ywroh

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!

Athena96 avatar Jul 22 '21 20:07 Athena96

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

jcmartinezdev avatar Jul 22 '21 20:07 jcmartinezdev

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?

jcmartinezdev avatar Jul 22 '21 21:07 jcmartinezdev

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.

joelvarty avatar Jul 23 '21 15:07 joelvarty

@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

jcmartinezdev avatar Jul 27 '21 10:07 jcmartinezdev

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 avatar Jul 27 '21 21:07 Athena96

@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.

Athena96 avatar Jul 27 '21 21:07 Athena96

@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 avatar Jul 29 '21 13:07 Nick-Navarro

@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.

Nick-Navarro avatar Jul 29 '21 17:07 Nick-Navarro

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

drmzio avatar Aug 05 '21 23:08 drmzio

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 🤷

stefanoeb avatar Sep 10 '21 09:09 stefanoeb

@Athena96

This does not work for us. Here is our next.config.js:

module.exports = {
  env: {
    MG_API_KEY: process.env.MG_API_KEY,
  },
  webpack: (config, { isServer }) => {
    // Fixes npm packages that depend on `ws` module
    if (!isServer) {
      config.node = {
        ws: "empty",
      };
    }

    return config;
  },
};

The MG_API_KEY variable is still undefined in the Lambda function.

sakhmedbayev avatar Oct 05 '21 18:10 sakhmedbayev

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!

Solved for me!! Thanks!

DavBio avatar Oct 14 '21 10:10 DavBio

This is not a nice solution for CDK users. How can we import environment variables from CDK? SST offers a CDK stack for Next.js with environment variables https://docs.serverless-stack.com/constructs/NextjsSite

joekendal avatar Oct 14 '21 17:10 joekendal

@joekendal, you would follow the same approach as the environment variable set up with the AWS CLI or CDK. The only difference is that the variable names also need to be referenced in the next.config.js, but that reference is to the var name that you set with the CDK/CLI above.

So, step 1 above can be handled by CDK.

siegerts avatar Oct 14 '21 18:10 siegerts

AWS_BRANCH

Even though this workaround works, it's a bad practice, you'll be exposing keys to all the environments

marianocodes avatar Oct 20 '21 17:10 marianocodes