Serverless 1.2 Setting Environment Variables and Nested Variables

Hello there,

I’ll just get right to it, I’m trying to setup the serverless file, playing around with the setup up.

Regarding the Environment variable I’ve been trying to do the following in the yml file:

feat_prefix: dev
test_prefix: test
dev_prefix: dev
prod_prefix: prod

provider:
name: aws
stage: local
region: ap-southeast-1
environment:
PREFIX: ${self:${opt:stage, self:provider.stage}_prefix}

When I deploy the lambda up it doesn’t seem to add the Environment variable, however if I don’t nest the variable such as above, I do see the PREFIX being set with the stage such as test,…

Based on the doc I don’t see what I am doing wrong to retrieve the respective value, but if anyone can correct me my understanding on nested variables, that could be great.

Thanks,

Rax

1 Like

@raxan92

Your custom variables need to be in the custom section. Use this instead.

custom:
  feat_prefix: dev
  test_prefix: test
  dev_prefix: dev
  prod_prefix: prod

provider:
  name: aws
  stage: local
  region: ap-southeast-1
  environment:
    PREFIX: ${self:custom.${opt:stage, self:provider.stage}_prefix}

Rich

1 Like

Hey Rich,

Thanks for the reply. I kinda went about relocating the other variables to an env.yml and calling them in.
The environment variable PREFIX wasn’t being set probably because it wasn’t recognized as a string. I’m not sure if putting them into custom in your example would be another solution, I’ll make sure to try it out and find out.

The other issue I encountered that’s similar was when I was trying to add in ${self:${opt:stage}_prefix} into a string which threw the error "Trying to populate non string value into a string…"
I assumed that values set are string by default for no reason and didn’t completely take in that error when it was thrown. I know better now at the very least.

Please do correct me if I’m wrong, I’m still new to serverless and lambda would like to have the right understanding on things.

Rax

Can you give me a high level overview of what you’re trying to do/achieve? From the first post it looked like you’re having trouble setting an environment variable called PREFIX but after the second post I’m confused (talking about using env.yml can calling in variables, etc.)

Are you just trying to have different values in your environment for each stage?

Rich

Hey Rich,

Yup, basically, I’m trying to set different values for each stage, the prefix will be used to prefix tables according to the stage. Sorry for not being clear, I was using that as a test case, where I was trying to set the variable PREFIX according to the stage but when I deployed the lambda, I didn’t see the environment variable being set on the console page for the test lambda.

It was probably unnecessary to mention the rest of the problems. In anycase thank you :grin:

Regards,

Sarkunan

That makes this a lot easier to answer and gives your more options.

If you only want to prefix table names with the stage you can do something like:

custom:
  stage: "${opt:stage, self:provider.stage}"
  myTable: "${self:custom.stage}-my-table"

provider:
  environment:
    MY_TABLE: "${self:custom.myTable}"

resources:
  Resources:
    MyTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:custom.myTable}

Inside your code use process.env.MY_TABLE to reference the correct table.

At some point you’ll probably end up with environment variable that can’t simply be prefixed (API keys or username/password for example). When that happens you can put this into serverless.yml

custom:
  stage: "${opt:stage, self:provider.stage}"
  myTable: "${self:custom.stage}-my-table"

provider:
  environment: ${file(env.yml):${self:custom.stage}}

resources:
  Resources:
    MyTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:custom.myTable}

Then inside your env.yml put:

dev:
  MY_TABLE: "${self:custom.myTable}"
  API_KEY: "Development API key"

prod:
  MY_TABLE: "${self:custom.myTable}"
  API_KEY: "Production API key"

I’ve got a more detailed write-up of this at Using Environment Variables with the Serverless Framework. I’ll update it in the next day to better cover your scenario.

3 Likes

Hey Rich,

Thank you for that example, its a lot more clearer to me now and thanks for the write up! I actually found that after posting the question here. Hope to see it updated :slight_smile:

Thanks again, have a good day!

Hey Rich,

I am currently trying to setup my environment variables, and have followed the process you have outlined here and in the write-up. I created the env.yml file and it is in the same directory as my serverless.yml file and reference it like so:

environment: ${file(env.yml):${self:custom.stage}}

However, I can’t seem to get it working.

I can set up an env var like this which outputs the stage correctly:
environment: MY_VAR: ${self:custom.stage}

So it seems my env.yml file is not being referenced correctly. Do I need to change the way I reference the vars in code (currently I do it like this: process.env.MY_VAR)? Or do I need to include the env.yml as a resource or something like that? I feel like I have missed a step somewhere. I hope this makes sense and you can identify what I’ve done wrong!

Cheers!
Bernd

Hey Bernd

What you’ve posted looks right. Could you post your env.yml? The problem is most likely in that.

Rich

Sure. I have since gotten around this issue by allowing my env.yml file to be included in my repo (by removing it from .gitignore). Obviously when I was building the project the env.yml file wasn’t there, and as such didn’t get included resulting in undefined variables.

But for anyone else who might need a similar solution, my env.yml file is included below. The secret variables are set in the GitLab repo, so although I am committing env.yml to my repo, the values are still obscured.

# env.yml
develop:
  TEST_VAR: 'the dev value'

staging:
  TEST_VAR: 'the staging value'
  DB_HOST: ${env:DB_STAGING_HOST}
  DB_USER: ${env:DB_STAGING_USER}
  DB_PASSWORD: ${env:DB_STAGING_PASSWORD}
  DB_NAME: ${env:DB_STAGING_NAME}
 

production:
  TEST_VAR: 'the prod value'
  DB_HOST: ${env:DB_HOST}
  DB_USER: ${env:DB_USER}
  DB_PASSWORD: ${env:DB_PASSWORD}
  DB_NAME: ${env:DB_NAME}

Are you deploying from a different machine? If you are then you need to have the env.yml on that machine too :slight_smile:

I wouldn’t recommend putting your env.yml into version control as it defeats the main purpose for having it in its own file (anyone with access to version control can see your credentials). Normally each developer would have their own env.yml and only the person (or machine) deploying to production would have the production credentials.

I had a problem where my env vars were not updating, and it seems you must deploy using sls deploy (not sls deploy function). I don’t know if that was your issue, but it solved it for me!

http://forum.serverless.com/t/accessing-stage-or-env-variables-in-lambda/911/7