Why Trigger Lambda from Jenkins?
Sometimes you need to kick off an AWS Lambda function as part of a deployment pipeline, run a data migration, or trigger a backend job on demand without building a full event-driven architecture. Jenkins gives you a familiar UI, audit logs, parameterized builds, and role-based access — making it a solid control plane for manual Lambda invocations during release workflows.
In this tutorial we will build a Jenkins declarative pipeline that authenticates to AWS, invokes a Lambda function synchronously, captures the response payload, and fails the build if Lambda returns an error code. Everything runs from a single Jenkinsfile you can commit to your repo today.
Prerequisites
Before you start, make sure you have the following in place:
- Jenkins 2.387+ with the AWS Credentials plugin and Pipeline plugin installed.
- An IAM user or IAM role attached to the Jenkins agent with at least the
lambda:InvokeFunctionpermission on the target function. - AWS CLI v2 installed on the Jenkins agent (or use the official AWS CLI Docker image as the agent).
- A Lambda function already deployed. We will use a function named
my-data-processorinus-east-1.
Store AWS Credentials in Jenkins
Go to Manage Jenkins → Credentials → (global) → Add Credentials. Choose AWS Credentials as the kind, enter your Access Key ID and Secret Access Key, and set the ID to aws-lambda-invoker. This ID is what the pipeline references — never hard-code keys in the Jenkinsfile.
If your Jenkins agents run on EC2 with an instance profile, you can skip this step and remove the withCredentials block from the pipeline. The AWS CLI will pick up the instance metadata automatically.
The Jenkinsfile
Create a file named Jenkinsfile in the root of your repository and paste the following pipeline. Read the inline comments — they explain every decision.
pipeline {
agent any
parameters {
string(
name: 'LAMBDA_FUNCTION',
defaultValue: 'my-data-processor',
description: 'Name or ARN of the Lambda function to invoke'
)
string(
name: 'AWS_REGION',
defaultValue: 'us-east-1',
description: 'AWS region where the function lives'
)
text(
name: 'PAYLOAD',
defaultValue: '{"action": "run", "env": "staging"}',
description: 'JSON payload to send to Lambda'
)
}
environment {
RESPONSE_FILE = 'lambda_response.json'
}
stages {
stage('Validate Payload') {
steps {
script {
// Fail fast if the payload is not valid JSON
def payload = params.PAYLOAD.trim()
try {
readJSON text: payload
echo "Payload is valid JSON."
} catch (Exception e) {
error "PAYLOAD parameter is not valid JSON: ${e.message}"
}
}
}
}
stage('Invoke Lambda') {
steps {
withCredentials([[
$class: 'AmazonWebServicesCredentialsBinding',
credentialsId: 'aws-lambda-invoker',
accessKeyVariable: 'AWS_ACCESS_KEY_ID',
secretKeyVariable: 'AWS_SECRET_ACCESS_KEY'
]]) {
script {
def function = params.LAMBDA_FUNCTION.trim()
def region = params.AWS_REGION.trim()
def payload = params.PAYLOAD.trim()
echo "Invoking Lambda function: ${function} in ${region}"
// --cli-binary-format raw-in-base64-out is required
// for AWS CLI v2 when passing a raw JSON string.
// The exit code of the CLI call reflects HTTP errors,
// NOT the FunctionError field — we check that separately.
def cliStatus = sh(
script: """
aws lambda invoke \\
--region ${region} \\
--function-name ${function} \\
--invocation-type RequestResponse \\
--cli-binary-format raw-in-base64-out \\
--payload '${payload}' \\
${RESPONSE_FILE}
""",
returnStatus: true
)
if (cliStatus != 0) {
error "AWS CLI returned non-zero exit code ${cliStatus}. Check agent IAM permissions and function name."
}
// Archive the raw response so it appears in Build Artifacts
archiveArtifacts artifacts: RESPONSE_FILE, fingerprint: true
}
}
}
}
stage('Check Lambda Response') {
steps {
script {
def response = readJSON file: env.RESPONSE_FILE
echo "Lambda response: ${groovy.json.JsonOutput.toJson(response)}"
// Lambda wraps unhandled errors in a FunctionError field.
// A handled error returned as a normal JSON body will NOT
// set FunctionError, so add your own status field if needed.
if (response.FunctionError) {
error "Lambda reported a FunctionError: ${response.FunctionError}. See ${env.RESPONSE_FILE} artifact for details."
}
// Optional: check a custom status field your function returns
if (response.statusCode && response.statusCode != 200) {
error "Lambda returned non-200 statusCode: ${response.statusCode}"
}
echo "Lambda invocation succeeded."
}
}
}
}
post {
always {
echo "Pipeline finished. Response file saved as build artifact."
}
failure {
echo "Pipeline FAILED. Review the console log and the lambda_response.json artifact."
}
success {
echo "Lambda invoked successfully. All checks passed."
}
}
}
How the Pipeline Works Step by Step
Validate Payload uses the Pipeline Utility Steps plugin’s readJSON to parse the text parameter before any AWS call is made. This catches typos early and avoids a confusing CLI error later.
Invoke Lambda wraps the AWS CLI call inside withCredentials so the access key and secret are injected as environment variables and masked in the console log. The --invocation-type RequestResponse flag makes the call synchronous — Jenkins waits for Lambda to finish. The response payload is written to lambda_response.json and immediately archived as a build artifact so you can download it from the Jenkins UI.
Check Lambda Response reads the JSON file and inspects two things: the FunctionError field that AWS sets for unhandled exceptions, and an optional statusCode field your function can return. If either signals a problem, the stage fails with a descriptive message.
IAM Policy for the Jenkins Agent
Attach a policy like this to the IAM entity used by Jenkins. Replace the ARN with your actual function ARN to follow least-privilege principles:
{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": "lambda:InvokeFunction", "Resource": "arn:aws:lambda:us-east-1:123456789012:function:my-data-processor" }] }
Running the Pipeline
Commit the Jenkinsfile, create a new Pipeline job in Jenkins pointing to your repository, and click Build with Parameters. You will see three input fields: function name, region, and payload. Fill them in and hit Build. The console output will show the Lambda response in real time, and the JSON file will appear under Build Artifacts when the run completes.
Tips and Next Steps
If your Lambda execution time exceeds 30 seconds, consider switching --invocation-type to Event for an asynchronous fire-and-forget call, but note you will not get a response payload back. You can also add a choice parameter for environment selection and use it to build the function name dynamically, for example my-data-processor-${ENV}. Finally, wrap the whole pipeline in a shared library if you need to invoke Lambda from multiple Jenkinsfiles across your organisation — the logic stays in one place and every team gets the same error handling for free.
