Skip to main content

Environment Variables

SST has built-in support for loading environment variables from a .env file into process.env using dotenv.

This is similar to what Create React App and Next.js do for environment variables.

For example if you add the following .env file to your project root.

.env
TABLE_READ_CAPACITY=5
TABLE_WRITE_CAPACITY=5

SST will load the process.env.TABLE_READ_CAPACITY and process.env.TABLE_WRITE_CAPACITY variables into the Node.js environment; automatically allowing you to use them in your CDK code.

Types of .env files

Aside from the default .env file, there are a couple of other types of .env files. You can use them to better organize the environment variables in your SST app.

.env.$STAGE

You can add a .env.$STAGE file to override the default values for a specific stage. For example, this overrides the value for the prod stage:

.env.prod
TABLE_READ_CAPACITY=20

.env*.local

You can also add .env.local and .env.$STAGE.local files to set up environment variables that are specific to your local machine.

.env.test

For your tests, you can add a .env.test file to override the default values when running npx sst test.

Priority

Here's the priority in which these files are loaded. Starting with the one that has the highest priority.

  1. .env.dev.local
  2. .env.dev
  3. .env.local
  4. .env

Assume that the current stage is dev.

And here's the priority when running your tests.

  1. .env.test
  2. .env.local
  3. .env

Committing .env files

The .env, .env.$STAGE, and .env.test files can be committed to your Git repository. On the other hand, the .env.local and .env.$STAGE.local shouldn't.

The .env*.local files are meant to specify sensitive information specific to your machine. They should be ignored through the .gitignore file.

caution

Don't commit any .env files to Git that contain sensitive information.

Note that, SST doesn't enforce these conventions. They are just guidelines that you can use to organize your environment variables. Similar to the ones used by Create React App and Next.js.

Expanding variables

SST will also automatically expand variables ($VAR). For example:

DEFAULT_READ_CAPACITY=5
USERS_TABLE_READ_CAPACITY=$DEFAULT_READ_CAPACITY
POSTS_TABLE_READ_CAPACITY=$DEFAULT_READ_CAPACITY

If you are trying to use a variable with a $ in the actual value, it needs to be escaped, \$.

NAME=Spongebob

# becomes "Hi Spongebob"
GREETING=Hi $NAME

# becomes "Hi $NAME"
GREETING=Hi \$NAME

Other environment variables

The .env environment variables will not modify an environment variable that has been previously set. So if you run the following:

NAME=Spongebob npx sst deploy

While your .env has.

NAME=Patrick

The .env value will be ignored and process.env.NAME will be set to Spongebob.

Environment variables in Seed

The above idea also applies to environment variables that are set in Seed or other CIs. If you have an environment variable set in Seed, it'll override the one you have set in your .env files.

Environment variables in Lambda functions

The .env environment variables are only available in your CDK code.

You can also set them as Lambda environment variables by including them in the Function environment prop:

new Function(this, "MyFunction", {
handler: "src/api.main",
environment: {
MY_ENV_VAR: process.env.MY_ENV_VAR,
},
});

Or you can use the App's setDefaultFunctionProps method to set it for all the functions in your app.

stacks/index.js
export default function main(app) {
app.setDefaultFunctionProps({
environment: { MY_ENV_VAR: process.env.MY_ENV_VAR },
});

new MySampleStack(app, "sample");
}

Built-in environment variables

IS_LOCAL

SST sets the IS_LOCAL environment variable to true by default when running inside sst start, the Live Lambda Development environment.

The process.env.IS_LOCAL is set in both the CDK and Lambda function code.

So in your CDK code you can do something like.

stacks/MyStack.js
export default class MyStack extends sst.Stack {
constructor(scope, id, props) {
super(scope, id, props);

// Increase the timeout locally
const timeout = process.env.IS_LOCAL
? 900
: 15;

// Rest of the resources
}
}

And in your Lambda functions.

src/lambda.js
export async function main(event) {
const body = process.env.IS_LOCAL
? "Hello, Local!"
: "Hello, World!"

return {
body,
statusCode: 200,
headers: { "Content-Type": "text/plain" },
};
}

Working with secrets

While it is common to use .env*.local files to store sensitive information (and not committing them to Git); the recommended way to work with secrets is to use AWS Systems Manager Parameter Store (SSM).

In this section let's compare the different ways secrets can be managed in SST. You can compare the different strategies and select the one that is right for you.

1. Use the .env*.local files

  • Usage in CDK: Reference via the the process.env
  • Usage in Lambda: Set via the Function's environment prop
  • Local usage: Store the secret in the .env*.local files that aren't committed to Git
  • CI usage: Store the secrets in the CI's dashboard
  • Security: GOOD, but the secrets are exposed to the CI providers and exposed in the CloudFormation template

2. Fetch SSM values in CDK using the AWS SDK

  • Usage in CDK: Use the AWS SDK to fetch the SSM values
  • Usage in Lambda: Set via the Function's environment prop
  • Local usage: Store the SSM paths in a .env file
  • CI usage: SSM paths loaded from the .env file
  • Security: BETTER, secrets are not exposed to CI providers, but they are displayed in plain text in Lambda console and the CloudFormation template

3. Fetch SSM values in Lambda using the AWS SDK

  • Usage in CDK: Cannot be used in CDK since it is resolved on deploy
  • Usage in Lambda: Fetch the SSM values inside a Lambda function using the AWS SDK
  • Local usage: Store the SSM paths in a .env file
  • CI usage: SSM paths loaded from the .env file
  • Security: BEST, secrets are not exposed to CI providers, Lambda console, or the CloudFormation template

In summary, while approach #1 is the easiest it is also the least secure. On the other hand #3 is the most secure but is not as easy to implement. We recommend using .env for variables that aren't as sensitive and relying on SSM for the most sensitive values.