Steve Kinney

Lambda Environment Variables

Environment variables work the same way in Lambda as they do in Vercel or Netlify: you set key-value pairs on the function, and your code reads them from process.env. The API endpoint for a third-party service, the name of a DynamoDB table, a feature flag—anything that changes between environments or shouldn’t be hardcoded goes into an environment variable.

If you want AWS’s exact rules and limits in front of you while you read, the Lambda environment variables guide is the official reference.

If you’ve ever set NEXT_PUBLIC_API_URL in a .env.local file or configured environment variables in the Vercel dashboard, you already understand the concept. The only difference is how you set them.

Setting Environment Variables via CLI

You can set environment variables when you create the function or update them on an existing function. Here’s how to add them during creation:

aws lambda create-function \
  --function-name my-frontend-app-api \
  --runtime nodejs20.x \
  --role arn:aws:iam::123456789012:role/my-frontend-app-lambda-role \
  --handler handler.handler \
  --zip-file fileb://function.zip \
  --environment 'Variables={TABLE_NAME=my-frontend-app-data,STAGE=production}' \
  --region us-east-1 \
  --output json

To update environment variables on an existing function, use update-function-configuration:

aws lambda update-function-configuration \
  --function-name my-frontend-app-api \
  --environment 'Variables={TABLE_NAME=my-frontend-app-data,STAGE=production,LOG_LEVEL=info}' \
  --region us-east-1 \
  --output json

In the console, the Configuration → Environment variables section shows all variables in plain text with an Edit button that lets you add, modify, or remove them.

The Lambda function Configuration tab showing the Environment variables section with TABLE_NAME set to frontend-items.

The --environment flag replaces all environment variables on the function, not just the ones you specify. If your function has three existing variables and you run update-function-configuration with only two, the third variable is deleted. Always include every variable you want the function to have.

Accessing Environment Variables in Your Handler

In your TypeScript handler, environment variables are available through process.env, exactly like they are in any Node.js application:

import type { APIGatewayProxyHandlerV2 } from 'aws-lambda';

const tableName = process.env.TABLE_NAME;
Note Reading process.env at the top level runs once during init, not on every invocation.const stage = process.env.STAGE ?? 'development';

export const handler: APIGatewayProxyHandlerV2 = async (event) => {
  if (!tableName) {
    return {
      statusCode: 500,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ error: 'TABLE_NAME environment variable is not set' }),
    };
  }

  return {
    statusCode: 200,
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      table: tableName,
      stage,
      message: 'Configuration loaded successfully',
    }),
  };
};

There are two patterns worth noting here. First, reading environment variables at the top level (outside the handler function) means the value is read once during the init phase and reused across invocations. This is more efficient than reading process.env on every request. Second, always validate that required environment variables exist—process.env.TABLE_NAME is string | undefined in TypeScript, and your function should fail clearly if a variable is missing rather than silently breaking.

Lambda’s Built-In Environment Variables

Lambda also sets several environment variables automatically. You don’t configure these—they’re always present:

VariableValue
AWS_REGIONThe function’s region (e.g., us-east-1)
AWS_LAMBDA_FUNCTION_NAMEThe function name
AWS_LAMBDA_FUNCTION_MEMORY_SIZEAllocated memory in MB
AWS_LAMBDA_FUNCTION_VERSIONThe version of the function being executed
AWS_EXECUTION_ENVThe runtime identifier (e.g., AWS_Lambda_nodejs20.x)
_HANDLERThe handler setting (e.g., handler.handler)

These are useful for logging and debugging. For example, you might include AWS_REGION in log output to confirm your function is running where you expect. I like to log the function name and region on every cold start—it saves time when you’re debugging across multiple environments.

The 4 KB Limit

Lambda imposes a total limit of 4 KB on all environment variables combined—keys, values, and formatting included. This sounds small, and it is. A handful of short configuration values fit easily; a JSON blob containing your entire application configuration doesn’t.

If you’re hitting the 4 KB limit, that’s a signal that your configuration has outgrown environment variables. At that point, you should move configuration to Parameter Store, which you’ll cover in the secrets section. It supports values up to 8 KB per parameter (or 64 KB for advanced parameters) with no total limit on the number of parameters.

A practical rule of thumb: use environment variables for simple, non-sensitive values that your function needs at startup—table names, stage identifiers, feature flags, API endpoint URLs. Use Parameter Store or Secrets Manager for anything that’s sensitive, large, or needs to be shared across multiple functions.

When Not to Use Environment Variables

Environment variables are the right tool for configuration that:

  • Changes between environments (dev, staging, production)
  • Isn’t sensitive enough to warrant encryption at rest
  • Is small (a table name, a URL, a stage identifier)
  • Needs to be available immediately at function startup

They’re the wrong tool for:

  • API keys, database passwords, and tokens. These should go in Secrets Manager or Parameter Store’s SecureString type. Environment variables are visible to anyone with lambda:GetFunctionConfiguration permission, and they appear in the Lambda console in plain text. The secrets section covers secure configuration in detail.
  • Large configuration objects. If your config is approaching the 4 KB limit, move it to Parameter Store.
  • Configuration that changes frequently. Updating an environment variable requires update-function-configuration, which triggers a brief function update. For configuration you want to change without redeploying, Parameter Store lets you update the value and have your function pick it up on the next invocation (with appropriate caching).

Updating a Single Variable

Since the --environment flag replaces all variables, updating a single variable requires you to re-specify everything. This is annoying but manageable. One approach is to use get-function-configuration to read the current variables, modify the JSON, and pass it back:

# Get current environment variables
aws lambda get-function-configuration \
  --function-name my-frontend-app-api \
  --query 'Environment.Variables' \
  --region us-east-1 \
  --output json

This returns:

{
  "TABLE_NAME": "my-frontend-app-data",
  "STAGE": "production",
  "LOG_LEVEL": "info"
}

Then update with the modified set:

aws lambda update-function-configuration \
  --function-name my-frontend-app-api \
  --environment 'Variables={TABLE_NAME=my-frontend-app-data,STAGE=production,LOG_LEVEL=debug}' \
  --region us-east-1 \
  --output json

Environment Variables and Cold Starts

Environment variables are available during the init phase, which means you can safely read them in top-level module code. This is actually the recommended pattern: read configuration once during init and reuse it across invocations. Don’t read process.env inside your handler on every request—it works, but it wastes time doing something that only needs to happen once.

// Good: read once during init
const tableName = process.env.TABLE_NAME;

export const handler: APIGatewayProxyHandlerV2 = async (event) => {
  // tableName is already available here
};
// Works but wasteful: read on every invocation
export const handler: APIGatewayProxyHandlerV2 = async (event) => {
  const tableName = process.env.TABLE_NAME;
  // reads process.env on every single request
};

The performance difference is negligible for a single variable, but the pattern matters: top-level initialization is a Lambda best practice that pays off when you’re initializing database clients, parsing complex config, or loading cached data.

Your function is deployed, configured, and invocable. The last topic before you connect it to the internet via API Gateway is one that affects every API you build with Lambda: cold starts. In the next lesson, you’ll learn what causes them, how they affect latency, and what you can do about it.

Last modified on .