Creating and Using Lambda Layers with AWS SAM and Node.js

Creating and Using Lambda Layers with AWS SAM and Node.js


As your Lambda functions grow, you’ll want to avoid duplicating code or dependencies across functions. AWS Lambda Layers solve this by letting you package shared code (like libraries or utilities) once and reuse them across multiple Lambdas.

In this post, you’ll learn:

  • How to create a custom Lambda Layer with AWS SAM using Node.js

  • How to bundle it with esbuild using a Makefile

  • How to use AWS Lambda Powertools for TypeScript as a global logging layer




What is a Lambda Layer?

A Lambda Layer is a ZIP archive containing libraries, a runtime, or other dependencies. It’s extracted to the /opt directory in the Lambda runtime, making it perfect for sharing utility code or dependencies across functions.



Step 1: Create a Layer in Your SAM Project

Let’s create a utility layer (e.g., utils) to share code.

Directory structure:

my-sam-app/
β”œβ”€β”€ layers/
β”‚   └── utils/
β”‚       └── utils.js
β”‚       └── package.json
β”‚       └── tsconfig.json
β”‚       └── Makefile
Enter fullscreen mode

Exit fullscreen mode

Your utils.js could be something like:

export const greet = (name: string) => {
  return `Hello, ${name}!`;
};
Enter fullscreen mode

Exit fullscreen mode



Step 2: Use a Makefile with esbuild

The tsconfig.json:

{
  "compilerOptions": {
    "strict": true,
    "target": "es2023",
    "preserveConstEnums": true,
    "resolveJsonModule": true,
    "noEmit": false,
    "sourceMap": false,
    "module": "commonjs",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "./utils"
  },
  "exclude": ["node_modules", "**/*.test.ts"]
}
Enter fullscreen mode

Exit fullscreen mode

Create a Makefile inside the utils/ folder:

build-Utils:
    npm install
    npm run build
    mkdir -p "$(ARTIFACTS_DIR)/nodejs/node_modules"
    cp package.json package-lock.json "$(ARTIFACTS_DIR)/nodejs/" # for runtime deps
    npm install --omit=dev --prefix "$(ARTIFACTS_DIR)/nodejs/" # for runtime deps
    rm "$(ARTIFACTS_DIR)/nodejs/package.json" # for runtime deps
    cp -r utils "$(ARTIFACTS_DIR)/nodejs/node_modules"
Enter fullscreen mode

Exit fullscreen mode

SAM will automatically pick this up when you run sam build.



Step 3: Define the Layer in template.yml

Resources:
  UtilsLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: utils-layer
      Description: Common utility functions
      ContentUri: layers/utils
      CompatibleRuntimes:
        - nodejs22.x
      RetentionPolicy: Retain
      Metadata:
        BuildMethod: makefile
Enter fullscreen mode

Exit fullscreen mode



Step 3: Attach Layer to Lambda Function

Now add it to your Lambda function:

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs22.x
      Layers:
        - !Ref UtilsLayer
    Metadata:
      BuildMethod: esbuild
      BuildProperties:
        Minify: true
        Target: "es2020"
        Sourcemap: false
        EntryPoints:
          - index.ts
        External:
          - utils
          - "@aws-sdk/*"
Enter fullscreen mode

Exit fullscreen mode



Step 4: Use Layer in Lambda Code

In your index.js or index.ts:

import { greet } from 'utils';

export const handler = async () => {
  return {
    statusCode: 200,
    body: JSON.stringify({ message: greet("SAM Developer") })
  };
};
Enter fullscreen mode

Exit fullscreen mode


🌟 BONUS: Using Powertools Logger as a Global Layer

If you want structured logging, tracing, and metrics β€” use AWS Lambda Powertools for TypeScript as a global layer. AWS provides it as a public layer:

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs18.x
      Layers:
        - !Sub 
arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:24
    Metadata:
      BuildMethod: esbuild
      BuildProperties:
        Minify: true
        Target: "es2020"
        Sourcemap: false
        EntryPoints:
          - index.ts
        External:
          - "@aws-lambda-powertools/*"
          - "@aws-sdk/*"
Enter fullscreen mode

Exit fullscreen mode

or globally:

Globals:
  Function:
    Layers:
      - !Sub arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:24
Enter fullscreen mode

Exit fullscreen mode

Example Use

import { Logger } from "@aws-lambda-powertools/logger";

const logger = new Logger({ serviceName: "MyApp" });

export const handler = async () => {
  logger.info("Lambda invoked");
  return {
    statusCode: 200,
    body: JSON.stringify({ message: "Logged with Powertools" })
  };
};

Enter fullscreen mode

Exit fullscreen mode




Conclusion

You now know how to:

  • Create a reusable Lambda Layer with esbuild

  • Structure a Makefile build process for SAM

  • Use AWS Lambda Powertools for structured logging


πŸ“š Previous Posts in the Series

1 – Mastering Serverless with AWS SAM

2 – Optimizing AWS SAM Node.js Lambda with esbuild

3 – Managing Environment Variables and Secrets in AWS Lambda (Node.js + SAM)



Source link

Leave a Reply

Your email address will not be published. Required fields are marked *