- Newest
- Most votes
- Most comments
Hello.
I added a layer to my AWS account using the steps in the document below and confirmed that files were created under "/opt".
https://docs.aws.amazon.com/lambda/latest/dg/nodejs-layers.html
I added the layer by running the following AWS CLI command:
mkdir nodejs
cd nodejs
mkdir certs
cd certs/
openssl genrsa -out whatever.pem 2048
cd ../../
zip -r layer.zip nodejs
aws lambda publish-layer-version --layer-name cert --zip-file fileb://layer.zip --compatible-runtimes nodejs22.x --region your-region
aws lambda update-function-configuration --function-name nodetest --cli-binary-format raw-in-base64-out --layers "arn:aws:lambda:your-region:your-aws-account-id:layer:cert:1"
I used the following code to check the files in "/opt".
import fs from 'fs';
import path from 'path';
export const handler = async (event) => {
const targetDir = '/opt';
try {
const listFiles = (dir) => {
const entries = fs.readdirSync(dir, { withFileTypes: true });
const results = [];
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
results.push(...listFiles(fullPath));
} else {
results.push(fullPath);
}
}
return results;
};
const files = listFiles(targetDir);
console.log("===== /opt file list =====");
console.log(files);
return {
statusCode: 200,
body: JSON.stringify({
message: `/opt contains ${files.length} file(s).`,
files,
}),
};
} catch (err) {
console.error("Error reading /opt:", err);
return {
statusCode: 500,
body: JSON.stringify({ error: err.message }),
};
}
};
As a result of execution, you can confirm that the following files have been created:
{
"statusCode": 200,
"body": "{\"message\":\"/opt contains 1 file(s).\",\"files\":[\"/opt/nodejs/certs/whatever.pem\"]}"
}
When you add a layer to a Lambda function, Lambda does extract the layer contents into the /opt directory, but there's a specific directory structure you need to follow for your layer content to be properly recognized.
For Node.js runtimes, your layer .zip file should have its dependencies in one of these folder paths:
nodejs/node_modulesnodejs/node18/node_modulesnodejs/node20/node_modulesnodejs/node22/node_modules
It appears that you zipped the certs directory directly, which isn't following the expected structure. When Lambda extracts this, it's not placing it in a location where your function can find it.
To fix this issue, you have two options:
-
Update your reference path: If you want to keep your current layer structure, you should reference the file using the full path where Lambda actually placed it. Try checking for the file in subdirectories of
/opt. -
Restructure your layer: The better approach is to restructure your layer .zip file. For non-code assets that should be accessible to all runtimes, you can place them in the
libdirectory within your .zip file. Lambda will extract this to/opt/lib.
For your specific case with a certificate file, try creating a .zip file with this structure:
lib/
certs/
whatever.pem
Then update your environment variable to point to /opt/lib/certs/whatever.pem.
Remember that when you're creating a layer, the directory structure inside the .zip file is important for Lambda to correctly place your files where your function can access them.
Sources
Managing Lambda dependencies with layers - AWS Lambda
Loading a csv file in a Lambda layer | AWS re:Post
Packaging your layer content - AWS Lambda
Deploy Node.js Lambda functions with .zip file archives - AWS Lambda
answered 9 months ago
I recreated my zip file to include lib as directed above, deleted and recreated my layer, changed my environment variable as directed above. No change in behavior, ls -R /opt still seems to return empty list. File (with new path) still shows load failure.
Relevant content
asked 2 years ago
- AWS OFFICIALUpdated 3 years ago

I had created the layer via the AWS UI instead of the CLI. This answer led me to two actions. First, I recreated the layer using the nodejs path as mentioned above. I'm not sure this was absolutely necessary given the other answer generated by AWS AI (...) didn't include that portion in the description of the use of /opt/lib. But, following my belief that working code wins I recreated the layer with the new path. The second piece it led me to was how to actually add the layer to the function. I had to look further into the UI than I had previously (scroll bars are a wonderful thing) to see where to add the layer to my function.
This is my first lambda function and my first layer, so obviously a newbie mistake.
Thanks for the pointers here.