When I first started building serverless functions, I was drawn to Go for one primary reason: speed. However, I quickly realized that deploying Go apps to AWS Lambda isn’t as simple as pushing code to a repository. Because Go is a compiled language, you have to ensure your binary is built for the specific Linux environment AWS uses, or you’ll be greeted by the dreaded /var/task/bootstrap: permission denied or exec format error.

In this tutorial, I’ll walk you through my proven workflow for getting a Go application from your local machine into production on AWS Lambda, focusing on the modern provided.al2023 runtime. If you’re wondering why use Go for cloud native development, the answer is usually the combination of low memory overhead and near-instant startup times—perfect for serverless.

Prerequisites

Step 1: Writing the Lambda Handler

AWS Lambda requires a specific handler function. Unlike a standard Go main() package that might start an HTTP server, a Lambda function uses the github.com/aws/aws-lambda-go/lambda package to listen for events.

package main

import (
	"context"
	"fmt"
	"github.com/aws/aws-lambda-go/lambda"
)

type MyEvent struct {
	Name string `json:"name"`
}

type MyResponse struct {
	Message string `json:"message"`
}

func HandleRequest(ctx context.Context, name MyEvent) (MyResponse, error) {
	return MyResponse{Message: fmt.Sprintf("Hello %s!", name.Name)}, nil
}

func main() {
	lambda.Start(HandleRequest)
}

Step 2: Compiling for the Lambda Environment

This is where most developers fail. You cannot simply run go build on a Mac or Windows machine and upload the result. You must cross-compile the binary for Linux and name it bootstrap to work with the provided.al2023 runtime.

Run the following commands in your terminal:

# Set target OS and Architecture
export GOOS=linux
export GOARCH=amd64

# Build the binary as 'bootstrap'
go build -o bootstrap main.go

# Zip the binary for upload
zip function.zip bootstrap
Terminal screenshot showing the exact GOOS and GOARCH environment variables and the resulting bootstrap binary
Terminal screenshot showing the exact GOOS and GOARCH environment variables and the resulting bootstrap binary

As shown in the image below, the bootstrap filename is mandatory for the custom runtime. If you name it main, AWS won’t know how to execute it.

Step 3: Deploying via AWS CLI

While the AWS Console is fine for beginners, I always recommend the CLI for repeatability. Use the following command to create your function:

aws lambda create-function \
    --function-name my-go-lambda \
    --runtime provided.al2023 \
    --handler bootstrap \
    --role arn:aws:iam::123456789012:role/lambda-ex \
    --zip-file fileb://function.zip

Note that the --runtime provided.al2023 flag tells AWS to use the latest Amazon Linux 2023 image, which is significantly faster and more secure than the older AL2.

Pro Tips for Go Lambdas

Troubleshooting Common Errors

If your function fails immediately, check these three things first:

  1. The filename: Is the binary named exactly bootstrap?
  2. The Architecture: Did you compile for amd64 but select arm64 (Graviton) in the AWS settings?
  3. Permissions: Does the binary have execution permissions? If you are building on a non-Linux machine and zipping, ensure the zip process preserves the executable bit.

What’s Next?

Now that you’ve mastered deploying Go apps to AWS Lambda, you might want to look into Lambda Layers for sharing common libraries or AWS SAM (Serverless Application Model) to manage your infrastructure as code. For those building larger systems, exploring how to optimize Go Docker image size is a great next step if you decide to move toward Fargate or Kubernetes.