If you just started looking into Serverless now, you could be forgiven for thinking that Serverless and Lambda are equivalent and interchangeable.
Even though Lambda may not have been the first-ever Serverless service, it most certainly is the product that kickstarted the "Serverless movement".
At face value, Lambda is an amazing service. The idea that we can spin up a powerful computing instance with virtually no setup involved, run our code on it, and pay a ridiculously low price for it (or nothing if there is no activity), is something that never ceases to blow my mind even after several years of building Serverless applications.
But Lambda and Serverless are not the same thing, and being Serverless doesn't mean just running code on Lambda. There are many other amazing services that qualify as Serverless.
Part of being Serverless means being able to choose the right service for the job at hand. Increasingly, this means replacing Lambda with another Serverless (or at least managed) service.
Some Good Reasons to Avoid Using Lambda
It's been said that the best code is no code at all. "Code is a liability" is another way some people use to express that concept.
In real-world terms, what that means is that ad hoc code is prone to errors. The more code you write, the higher the chance that something could go wrong.
On the other hand, by leveraging resources such as an existing open-source library1 or a managed cloud service, we reduce the chances of introducing new issues into our application.
Another compelling reason for avoiding Lambda is to reduce latency. Lambda functions can add extra latency to your application.
There are techniques to avoid that extra latency, and it's not hard to do. Nevertheless, if you're concerned with ensuring the snappiest possible response, you should consider skipping Lambda altogether.
A Few Ways to Avoid Using Lambda
Increasingly, as the Serverless ecosystem of services and capabilities expand, it is becoming possible to replace Lambda with direct integrations or connectors.
For example, if you're using AppSync to manage your GraphQL endpoints, writing a Javascript or VTL resolver can allow you to connect to your DynamoDB table much more efficiently.
Similarly, if you have a Lambda that is used to extract data from a third-party API endpoint, EventBridge API Destinations can entirely replace that Lambda and handle any retry and failure logic for you.
Step Functions allows you to replace your custom orchestration-like logic with a reliable, highly scalable state machine.
Finally, lots of basic operations can be handled from the frontend. Using the AWS SDK (or Amplify) you can, for example, upload and get data from the likes of S3 and DynamoDB. This means that it's not strictly necessary to invoke a Lambda-backed API to run those operations.
***
Although Lambda is often a synonym for serverless, it is sometimes more serverless to avoid it.
By delegating actions to managed services or direct integrations, you let the cloud do what it does best and reduce the amount of custom, error-prone code in the system.
That’s what serverless is all about.
Of course, an open-source library, like a managed service, could contain a bug. But a popular library/service will have been reviewed and tested at a bigger scale than what a single engineer could hope to do. This is what "standing on the shoulders of giants" looks like.