If you are thinking of moving your Java Spring Boot API to the serverless world, you may want to consider using AWS Lambda. We have already written about Java Spring Boot on AWS Fargate and NodeJS on AWS Lambda. But this time, we want to share how to deploy and monitor a small Java Spring Boot API on AWS Lambda, and we also want to present why this type of deployment–using these two services–is a good idea. So, first, a quick introduction:

  • AWS Lambda is the FaaS (function as a service) offering provided by Amazon. It has integrations with many other AWS services, including AWS DynamoDB and AWS API gateway. Due to its popularity and support for multiple languages, AWS Lambda is a safe move for going serverless. You can take a look at the getting started guide for more information. 

Now, on to our use case.

Use Case Scenario for Using Spring Boot + AWS Lambda

As it is inferred in our post covering the best use cases for AWS Lambda, one of the use cases for Lambda is the deployment of a Web Backend API. When it comes to serverless backend APIs, AWS Lambda is a preferred option due to its integrations with other AWS and third-party services. The FaaS model helps reduce costs associated with the provisioning and maintenance of the underlying hardware, and it also scales out of the box. All of this allows developers to spend more time building features and less time supporting the infrastructure. As to Spring Boot, it aims to make building a Java application easier, since it provides a lot of ready-to-use packages that, again, allow developers to focus more on building new features. 

By using Spring Boot together with AWS Lambda within the context of building a backend API, you get a win-win in terms of productivity. This is because both tools allow developers to concentrate on writing business logic code, and so developers will be able to deploy endpoints faster. 

What Are You Going to Deploy?

We’ve built a small API in Spring Boot already. In this post, we are now going to modify it a bit in order to deploy it to AWS Lambda. The API will consist of one endpoint, which will return a static list of books.

Booksapp endpoint

Essentially, we want to wrap up the endpoint described in the image above in a Spring Boot app and deploy them on AWS Lambda. The final code for this can be downloaded here.

Building Your Application

Let’s get started! Let’s deploy a small “Ping/Pong” app first and then, with a little more confidence, you will be able to update it to include the /books endpoint.


In order to deploy the API, you will need to have the following tools installed on your local machine:

Deploying a Java App on AWS Lambda

There are many options for deploying Java applications in AWS Lambda. If you’re wondering about using the Serverless Framework, follow this great post by Rupak Ganguly for getting started. But if you’re using traditional Java frameworks like Spring, Spring Boot, Jersey, or Spark, you can take advantage of the aws-serverless-java-container tool, as we do in this post.

The aws-serverless-java-container is a package created by AWS that behaves as a proxy between a Java Framework and AWS Lambda. This means that you can run your Java APIs on AWS Lambda with minimal code changes. 

For deploying a Java app with an aws-serverless-java-container, you will first need to install Apache Maven (instructions on this post will be Mac OS flavored, but you can always use similar commands for other platforms):

$ brew install maven
$ mvn --version
Apache Maven 3.6.2 (40f52333136460af0dc0d7232c0dc0bcf0d9e117; 2019-08-27T10:06:16-05:00)
Maven home: /usr/local/Cellar/maven/3.6.2/libexec

AWS has published the aws-serverless-java-container tool for different Java frameworks as a Maven archetype, meaning that you can create the scaffold for a ready-to-use app that is compliant with AWS Lambda using Maven commands. For creating an initial app, run the following command:

$ mvn archetype:generate -DgroupId=bookapp -DartifactId=book-service -Dversion=1.0-SNAPSHOT -DarchetypeGroupId=com.amazonaws.serverless.archetypes -DarchetypeArtifactId=aws-serverless-springboot-archetype  -DarchetypeVersion=1.4

Pay special attention to the parameter DarchetypeGroupId, which defines the supported Java Framework. The initial app provides a /ping endpoint, which returns “pong” as an answer. Something great about the code/structure generated by the aws-serverless-java-container tool is that it is already optimized for avoiding cold starts.

Building the App Locally 

For running the application locally, you can use the official AWS SAM CLI tool. To install the package on MacOS, run:

$brew tap aws/tap
$brew install aws-sam-cli
With the package installed, you can go to the application’s root folder, build the package, and run it locally.
$ cd myworkspace/book-service
$ mvn clean package
$ sam local start-api --template sam.yaml
Now, hit the local endpoint with:
$ curl -s

And verify that you are getting a “pong” answer.

Deploying an Endpoint

After verifying that the sample app is running locally, you can use AWS Cloud Formation for getting it on AWS lambda. In order to do so, you need an AWS S3 bucket for storing your template:

aws s3 mb s3://mybucket

With the bucket in place, it’s time to create the AWS CloudFormation template:

$ aws cloudformation package --template-file sam.yaml --output-template-file output-sam.yaml --s3-bucket mybucket

If everything is OK, you just need to deploy your newly created template with:

$ aws cloudformation deploy --template-file output-sam.yaml --stack-name bookApi --capabilities CAPABILITY_IAM

With this, you can check on your AWS account for a Lambda function that has an HTTP call as a trigger.

Checking the HTTP trigger

Building the Book Service

Now that you have deployed the initial application, you can update it to actually return a static payload related to books. The first task here is to add the Book Bean:

package bookapp.controller;
public class Book {
    private final long id;
    private final String name;
    private final String author;
    public Book(Long id, String name, String author) {
        this.id = id;
        this.name = name;
        this.author = author;
    public long getId() {
        return this.id;

    public String getName() {
        return this.name;

    public String getAuthor() {
        return this.author;

You then have to add the Book Controller:

package bookapp.controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import java.util.HashMap;
import java.util.Map;
public class BookController {
    private static final Book[] books = {
        new Book(1L, "Nemesis", "Isaac Asimov"),
        new Book(2L, "Great Expectations", "Charles Dickens"),
        new Book(3L, "The Chronicles of Narnia", "C.S. Lewis")
    @RequestMapping(path = "/books", method = RequestMethod.GET)
    public Book[] books() {
        return books;

Notice how in the repo the Book Bean is next to the Book Controller. This was done for simplicity, but in real applications, all beans should be located in a better place. With these two new components written, you can build and redeploy your application. 

Checking /books

Checking /books


Each function on AWS Lambda gets monitored automatically. You can see, for instance, most of the metrics collected by AWS in the following image:

AWS Monitoring

AWS Monitoring

By default, you will be able to see the number of invocations, the average duration of the function, and error rates, among other data. Also, AWS Lambda is integrated with AWS CloudWatch, so you can check the logs directly from the same section.

However, sometimes metrics are not enough. If you want to get full observability of your function, you may find cloud-native tools too limited. Here is where Epsagon monitoring solutions can help you out. By configuring the project with Epsagon’s library for Java, you can get a useful dashboard and architectural diagram that shows how your functions are connected and what they’ve been spending their time on. 

Epsagon Dashboard

Epsagon Dashboard

Epsagon Trace View

For instrumenting your function, you need to install the Epsagon library. You can simply add it as a dependency in your pom.xml:


With the dependency in place, you can now update your sam.yaml to add some environmental variables and to change the entry point of the AWS Lambda:


You can check the documentation here to learn how to instrument your functions. 


In this post, we’ve presented how to deploy a small Java Spring Boot API on AWS Lambda. We also talked about the aws-serverless-java-container tool, which allows you to deploy applications based on a Java framework on AWS Lambda with zero pain. Moreover, we demonstrated how to monitor Java Lambda functions using Epsagon’s solutions. 

Once you get Epsagon in place, you will have a clear picture of how your function is performing. But not only that, Epsagon also allows you to know how your functions are spending their time (calls to databases, calls to other APIs, and calls to other AWS services in general), thus giving you full observability of your code.

Try Epsagon for free