Cloud

Moving small client workloads to AWS Lambda

CLD

Most of our client work still lives on EC2 or shared application servers, but this year we started experimenting with AWS Lambda for small, event-driven pieces of larger systems. Nightly report generation, image thumbnail creation on S3 upload, and a couple of webhook receivers were our first candidates.

The appeal is obvious: no server to patch, and you pay only for the compute you actually use. For a client whose thumbnail job ran for ninety seconds every few hours, moving it off an always-on EC2 instance cut that piece of the bill to almost nothing. We measured the old instance's utilization before switching and found it sat idle well over ninety percent of the time, which made the case for Lambda an easy one to make internally even before the first invoice arrived.

It is not a drop-in replacement for a full application server yet. Cold starts are noticeable, especially for anything touching a VPC-bound database, since attaching a Lambda function to a VPC adds its own startup penalty on top of the language runtime's own cold-start cost. We measured a plain Node function cold-starting in well under a second, but the same function configured to reach into an RDS instance inside a VPC sometimes took three or four seconds on a cold invocation, which is enough to matter for anything user-facing.

The tooling around deployment and local testing is still rough compared to what we are used to with a normal Node or PHP app. Zipping up a function, uploading it through the console or the CLI, and waiting to see whether it actually invokes correctly in the cloud is a slower feedback loop than just running the app locally and refreshing a browser. We have started keeping our Lambda functions as plain, dependency-light modules specifically so we can run and test the core logic locally with a normal Node process before ever deploying it, treating the Lambda handler itself as a thin wrapper around code we can otherwise test the ordinary way.

A few other things worth flagging for anyone considering the same move: set a conservative but realistic timeout on each function, since the default is short and a function that occasionally needs a few extra seconds for a slow downstream call will fail intermittently if you do not raise it. Watch your memory allocation setting closely, since Lambda's CPU allocation scales with the memory you configure, and an under-provisioned function can be surprisingly slow even for simple work. Centralize logging output early, since debugging a function after the fact means digging through CloudWatch Logs rather than tailing a familiar log file on a server you can SSH into.

We are keeping our core applications on EC2 and reaching for Lambda only for the isolated, event-driven edges — that split has worked well so far, and we do not see a reason to push harder toward serverless for anything that needs to hold state or run continuously. For the right narrow jobs, though, it has already paid for itself several times over.

← Back to the journal

Have a project in mind?
Let’s talk.

Tell us where you are and where you want to go. We'll map the fastest route between the two.

Currently accepting new clients