Blog · Engineering
Build vs buy on AWS: when self-hosted compute beats managed.
Managed services bill per output; self-hosted compute has a near-fixed base. The two curves cross somewhere, and it pays to know where before you commit.

Some managed services have a price that's hard to argue with: you pay only when you use them, there's no infrastructure to maintain, and they scale without you thinking about it. Until volume grows and, at a certain scale, they charge ten times what it would cost to run the same thing yourself.
The trap isn't that managed is bad. It's that the price buys simplicity, and past a certain volume that simplicity stops being worth the multiple.
How much does each option cost as volume grows?
Take a managed service that bills per output (video transcoding, image transforms, OCR, whatever) and run the numbers:
Managed cost = official pricing × projected volume
Self-hosted cost = on-demand baseline compute + scale-out by queue depth
For a real workload I sized (multimedia files: video, images, PDFs and audio), it came out like this:
| Volume | Managed (projected) | Self-hosted (measured) |
|---|---|---|
| Current load | ~$6,000/yr | ~$600/yr |
| 2× load | ~$12,000/yr | ~$625/yr |
| 5× load | ~$30,000/yr | ~$680/yr |
The base barely moves. Managed scales exactly with usage.
At low volume managed wins: you're not paying for a server that mostly sits idle. As volume climbs, the per-output charges stack up, and self-hosted, with its near-fixed base, ends up far below.
How do you build the self-hosted option on AWS?
The pattern that worked for workloads like this: SQS in the middle, an EC2 auto-scaling group (ASG) below.
upload → SQS → ASG (on-demand baseline + scaling by queue depth) → output
SQS decouples: the upload finishes fast and processing starts when there's capacity. CloudWatch watches queue depth; the ASG adds instances when work piles up and removes them when the queue drains. An on-demand baseline instance guarantees minimum capacity during work hours.
Spot is tempting because of the price (50-70% below on-demand), but AWS can reclaim the instance with only two minutes of notice. If you were processing a file at that moment, the message stays invisible until the visibility timeout expires and then goes back to the queue.
It works if jobs are short and idempotent: retrying must be safe, and no partial state should be left orphaned in S3. It's a separate decision from the overall architecture. Start with on-demand and add spot later, if the numbers justify it and idempotency is solid.
One change that moves the math: shut the ASG down off-hours
Most B2B products don't have a uniform 24/7 load: a peak during office hours, almost nothing at night and nothing on weekends. The baseline instance costs the same at 3 AM as at 3 PM, even though at 3 AM it's processing nothing.
ASG scheduled actions fix this without changing the pattern:
- In the morning:
min_size = 1. The ASG starts the baseline before work hours. - At night:
min_size = 0. The ASG shuts everything down. - If a message arrives off-hours, queue-depth scaling policies can still spin up capacity, as long as you can tolerate a few minutes of cold start for that late job.
That recovers a good part of the idle cost without hurting daytime latency. It's the self-hosted equivalent of pay-per-use, but measured against your real working hours instead of the first message of the day.
Lambda wasn't an option for this load: the timeout is 15 minutes and the larger files took longer. If your workload fits in 15 minutes, Lambda + SQS may be all you need.
What costs don't show up on the AWS invoice?
The cloud price isn't the full price. When you build instead of buy, you take on what managed was hiding:
- ASG configuration and tuning: scale-up and scale-down policies, queue depth metrics, warmup periods.
- Retries and DLQs: errors stop being the provider's problem.
- Spot interruptions: rescheduling the job when AWS takes the instance back.
- Processing stack updates: new codecs, security patches, libraries that break.
- On-call: for when something goes down on a Sunday.
That operational complexity is real and concentrates in few hands. Today you maintain the pipeline; tomorrow it can become latent debt. If a requirement lands that managed solved with a toggle (DRM, multi-bitrate HLS, server-side ad insertion), implementing it yourself takes weeks.
When should you build, and when should you buy?
The rule I use:
- Low or unpredictable volume → buy. Managed bills when used; you don't pay a fixed base for idle infrastructure.
- High and predictable volume, with linear managed pricing → build. The fixed base becomes irrelevant.
- Exotic requirements (DRM, special formats, compliance) → buy, unless you have a dedicated team.
- Small team, on-call without redundancy → buy. The operational complexity outweighs the cost.
And the rule of thumb for deciding fast: if managed comes out 5× more expensive or more than the equivalent compute and scales linearly with demand, build it yourself. Run the numbers before you integrate, not after.
The price on each side
Managed bills you per minute of output. Self-hosted bills you in operational complexity. Neither is free.
The mistake is skipping the math and assuming managed is the default. Sometimes it is. Sometimes it isn't, and the difference compounds.