After we moved one workload out of Azure Functions, a reasonable question came up.
Why not move everything?
The answer was simple. Some things were still working exactly as intended.
Serverless did not fail us. We just learned where it fit.
Not All Functions Are Equal
One of the easiest mistakes to make with Azure Functions is treating them as interchangeable units.
They are not.
Some functions want to be long lived. Some want tight performance guarantees. Some want deep observability.
Others just want to run briefly and disappear.
We left the second category in serverless.
The Workloads That Stayed
The functions we kept shared a few characteristics.
They were:
- short running
- truly event driven
- tolerant of retries
- loosely coupled
- non critical to request latency
Most importantly, they did not require strong guarantees.
If they ran five seconds later, nothing broke. If they retried twice, nothing cascaded. If they scaled aggressively, costs stayed predictable.
The abstraction held.
Event Driven Still Means Event Driven
Serverless works best when the event matters more than the timing.
Things like:
- reacting to a message on a queue
- processing a file after upload
- syncing data between systems
- emitting notifications
In these cases, Azure Functions stayed out of the way.
We did not need to reason about workers or instances. We did not care how many were running. We only cared that the work completed eventually.
We have one function that processes uploaded files from Azure Blob Storage. It extracts metadata, validates the content, and writes results to a database. It runs hundreds of times a day. We’ve never had to think about scaling it.
When Observability Requirements Are Modest
Another common trait was visibility expectations.
For the functions we left in serverless:
- logs were enough
- basic metrics were sufficient
- tracing was helpful but not mandatory
We did not need deep insight into execution internals. We just needed to know when something failed.
Serverless was good at that level of abstraction.
The built-in Application Insights integration gives us invocation counts, failure rates, and execution times. For async workloads, that’s plenty.
Failure Was Acceptable
This part matters.
The functions that stayed could fail without causing immediate harm.
They were:
- asynchronous
- retry safe
- idempotent
- isolated from user facing flows
That gave us breathing room.
Serverless is much more forgiving when failure is an acceptable state.
Cost Behavior Stayed Predictable
We also paid attention to cost.
The functions that remained:
- ran infrequently or in bursts
- had bounded execution time
- did not fan out uncontrollably
Their cost profile stayed flat even as usage grew.
That predictability made them easy to leave alone.
The Consumption plan charges per execution and compute time. For workloads that run sporadically, that’s ideal. We have functions that process a few hundred events per day. Monthly costs are measured in dollars, not hundreds of dollars.
Compare that to running a dedicated worker that sits idle 23 hours a day. Serverless wins easily for that pattern.
The Mental Model Stayed Simple
The clearest signal was this.
We did not think about these functions very often.
They did their job. They did not page us. They did not show up in postmortems.
That is exactly what you want from serverless.
When a function becomes invisible in the best way possible—it just works, doesn’t break, doesn’t need tuning—that’s when you know serverless is doing what it’s supposed to do.
What This Taught Us
Serverless is not a default. It is a filter.
When a workload passes that filter, it stays simple. When it does not, friction builds quietly.
The mistake is not using serverless. The mistake is using it everywhere.
Final Thought
Good platform decisions are rarely absolute.
We moved one function out of serverless because it demanded predictability. We left others in serverless because they thrived on flexibility.
Knowing the difference is not about tools. It is about understanding the shape of the work.
That is what we left in serverless and why.
Still running Azure Functions? Not every workload needs to migrate. Know which ones benefit from the abstraction and which ones fight against it.