Build vs buy on AWS: when self-hosted compute beats managed.
Managed services bill per output. Self-hosted compute has a fixed base. The economics cross, and it pays to know where the crossover is before you commit.
Some managed services are great because of their pricing. They charge you only when you use them. No infrastructure to maintain. Scale without thinking. And at a certain scale, they're charging you 10× what it costs 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 no longer earns the multiple.
The math before you integrate
Take a managed service with output-based pricing (video transcoding, image transforms, OCR, whatever). 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 file processing: video, images, PDFs, audio), the numbers 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's mostly idle. As volume climbs, the per-output charges stack up, and the self-hosted line, with its near-fixed base, sits well below.
The shape of self-hosted
The pattern that works for workloads like this: SQS in the middle, EC2 with an auto-scaling group below.
upload → SQS → ASG (on-demand baseline + scaling by queue depth) → output
SQS decouples. The upload finishes fast and the processing is picked up when capacity is available. CloudWatch watches queue depth and the ASG scales out when work stacks up, scales in when the queue drains. An on-demand baseline instance guarantees minimum capacity during work hours.
About spot: tempting because of the price (50-70% less than on-demand), but AWS can reclaim the instance with two minutes of notice. For a job currently processing a file, that means the message stays invisible until the visibility timeout expires and it goes back to the queue. It works if jobs are idempotent and short: retries must be safe, no partial state left orphaned in S3. It's a decision separate from the overall architecture. Start with on-demand, add spot later if the numbers justify it and idempotency is solid.
The twist: if your load has hours, shut the ASG down off-hours
Most B2B products don't have 24/7 uniform load. Peak during office hours, almost nothing at night, zero on weekends. The on-demand baseline costs the same at 3 AM as at 3 PM, even though at 3 AM nothing's processing.
ASG scheduled actions solve this without changing the pattern:
- In the morning:
min_size = 1, ASG starts the baseline before work hours. - At night:
min_size = 0, ASG shuts everything down. - If a message arrives off-hours, queue-depth scaling policies can spin up capacity anyway, assuming you can tolerate a few minutes of cold-start for that late job.
That recovers a chunk of the idle cost without sacrificing daytime latency. It's the self-hosted equivalent of pay-per-use, but centered around when you actually work, not the first message of the day.
Lambda wasn't an option for this load: 15-minute timeout, and larger files took longer. If your workload fits in 15 minutes, Lambda + SQS might be all you need.
What self-hosted bills you off the invoice
The cloud price isn't the full price. When you build instead of buy, you take on what managed was hiding:
- ASG tuning and configuration, scale-up/down policies, queue depth metrics, warmup periods.
- Retries and DLQs, errors are no longer the provider's problem.
- Spot interruptions, rescheduling jobs when AWS pulls the instance.
- Processing stack updates, new codecs, security patches, libraries that break.
- On-call, when something breaks on a Sunday.
That operational complexity is real and concentrates in few hands. Today you maintain the pipeline. Tomorrow it's latent debt: if a requirement lands that managed solved with a toggle (DRM, multi-bitrate HLS, server-side ad insertion), it takes weeks to implement yourself.
When to build, when to buy
The rule I use:
- Low or unpredictable volume → buy. Managed bills when used, you don't pay a fixed base for idle infra.
- High and predictable volume, with linear managed pricing → build. The fixed base becomes irrelevant.
- Exotic managed features (DRM, special formats, compliance) → buy unless you have a dedicated team.
- Small team, on-call without redundancy → buy. The operational complexity outweighs the cost.
The rule of thumb to decide fast: if managed lands ≥5× more expensive than 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 not running the math and assuming managed is the default. Sometimes it is. Sometimes it isn't, and the difference compounds.