Go is well known for how it supports and models concurrency in its ecosystem. Providing constructs like Channels, WaitGroups and Goroutines to build concurrent programs.
One thing that kept me intrigued was how this would work in a serverless system; in this case specifically AWS Lambdas.
- Your runtime is not long lived, lasts only as long as your function runs
- You don’t want background Goroutines either they’d get killed once the main handler returns
- Lets not forget the compute costs that add up the longer they run
- Core allocation when running lambdas is not transparent
Does this limitation really matter? Goroutines don’t directly map to OS threads, so you could still design your code to run concurrently. By moving blocking, I/O bound tasks into goroutines, you can unlock performance improvements by making operations concurrent and non-blocking; just like how Nodejs handles asynchronous tasks.
Before diving deeper, let’s verify that this approach actually works as expected on AWS Lambda. Demo time:
Running this code as an AWS lambda confirms that, regardless of the allocated CPU cores you can execute concurrent programs on Lambda (or any serverless runtime). Since Lambda does not allow you to choose core count explicitly, I tested this in multiple memory configurations.
The outputs were similar across multiple terms of how concurrent the execution was. Sample logs below:
START RequestId: 4dfaf7ca-9981-4b2a-a50c-099d7dd4c1b2 Version: $LATEST
placing order: deli pizza for table: 4
processing order: deli pizza for table: 4
delivering order: deli pizza for table: 4
placing order: pepperoni pizza for table: 1
processing order: pepperoni pizza for table: 1
delivering order: pepperoni pizza for table: 1
placing order: veggie pizza for table: 2
processing order: veggie pizza for table: 2
delivering order: veggie pizza for table: 2
placing order: pepperoni pasta for table: 3
processing order: pepperoni pasta for table: 3
delivering order: pepperoni pasta for table: 3
END RequestId: 4dfaf7ca-9981-4b2a-a50c-099d7dd4c1b2
REPORT RequestId: 4dfaf7ca-9981-4b2a-a50c-099d7dd4c1b2 Duration: 1.35 ms Billed Duration: 2 ms Memory Size: 1024 MB Max Memory Used: 21 MB
Should You Use Goroutines Inside Lambda?
For CPU‑bound tasks, creating many goroutines (e.g., 100) usually provides little benefit. They will time‑slice on the single vCPU allocated to the Lambda. Lambda allocates CPU power based on memory for example, ~1 vCPU for 1,769 MB of memory.
Using concurrency inside a single Lambda to scale workloads defeats the purpose of Lambda. AWS already handles horizontal scaling by running multiple parallel executions.
Goroutines are useful for I/O‑bound tasks (HTTP calls, DB queries, S3 operations). They let you run these operations in parallel within one request. This can reduce latency and improve throughput without extra cost.
Key considerations
- Short‑lived and stateless: If goroutines are still running after the handler returns, they will be terminated.
- Cold starts: More concurrency in one function might mean bigger binaries and longer cold starts.
- Billing model: Lambda charges per function execution time, not per goroutine. Splitting work across multiple Lambda invocations is often cheaper and scales more effectively.
- Error handling: Panics in goroutines don’t automatically fail the Lambda unless explicitly handled, which can lead to silent failures.