The Day I Deployed an API for €0.02 per Month
A client needed a contact form on their Next.js site hosted on Vercel. Nothing crazy. Receive a name, email, message, send it via SendGrid. The kind of thing you knock out in 30 minutes.
I created an Azure Function App using the .NET isolated worker model, wrote the function, ran `dotnet publish`, deployed via Azure CLI. From first keystroke to a working contact form in production: 15 minutes. Monthly cost? €0.02. Not two euros. Two cents.
The architecture was dead simple:
``` Client → Vercel (Next.js) → Azure Function App → SendGrid → Email ```
Four components. Zero servers to manage. And an Azure bill that doesn't exceed the price of a coffee per year.
This is the kind of experience that convinced me Azure is a solid choice for European SMBs. Not because it's perfect, nothing is, but because the cost-to-outcome ratio is hard to beat when you know where to step.
The Consumption Plan: Start Here
The economics of Azure Functions on a consumption plan are brutal (in a good way). You pay per execution. No server running 24/7 waiting for requests. If nobody calls your API on a Sunday, you pay zero.
The first million executions per month are free. For an SMB, that covers the majority of use cases. A webhook, an internal API, file processing, all of it runs for pennies.
My practical advice: start with a consumption plan. When your Function App starts costing more than €30/month, switch to a dedicated plan. Before that, you're optimizing a problem that doesn't exist.
The classic trap is jumping straight to an App Service Plan B1 or B2 "just in case." I've seen clients paying €50/month for workloads that would have cost €3 on consumption. Resist the urge to over-provision.
The .NET Isolated Worker Model: The Right Call
Since .NET 5, Microsoft has been pushing the isolated worker model for Azure Functions. And they're right to. The in-process model is end-of-life.
The isolated worker gives you control over the runtime. You manage your own `Program.cs`, your dependency injection, your middleware. It's standard .NET. If you know how to build an ASP.NET Core API, you know how to build an isolated worker Function App.
In practice, I use .NET 8 (soon .NET 10) with the `Microsoft.Azure.Functions.Worker` package. The structure is clean: a `Program.cs` for bootstrapping, function classes with trigger attributes, and that's it. No black magic.
GDPR and the West Europe Region
If you work with European clients, the GDPR question comes up every time. "Where is our data stored?" It's a fair question.
Azure makes this straightforward. You pick the West Europe region (Netherlands) or France Central (Paris) and your data stays in Europe. Period. No transatlantic transfers, no contractual clauses to negotiate.
I deploy everything to West Europe by default. Latency is excellent from France, Belgium, Morocco. And when a client asks for proof of compliance, I show them the Azure configuration, the region is right there in black and white.
Azure DevOps for CI/CD
GitHub Actions is trendy. But for SMBs already on Microsoft 365, Azure DevOps remains a coherent choice. Everything lives in the same place: repos, pipelines, boards.
My typical pipeline for a Function App:
- Push to `main`
- .NET build + tests
- `dotnet publish` in Release mode
- Deploy to Azure via a service connection
Four steps. The YAML is 40 lines. It runs in 2 minutes.
The underrated advantage of Azure DevOps is the 1,800 free build minutes per month on hosted agents. For an SMB deploying a few times a week, that's more than enough.
App Insights: Observability Without the Headache
I used to neglect monitoring. "It works, why watch it?" Until a Function App for an IoT client, an industrial packaging machinery company, started timing out on certain MQTT messages without anyone noticing for three days.
Since then, Application Insights is enabled on everything. The SDK integrates in one line in `Program.cs`. You get response times, exceptions, dependencies, traces, the full picture.
Live Metrics is a genuine pleasure to use. You see in real time what's happening in your app. When you deploy to production on a Friday at 5 PM (we've all done it), it's reassuring to have a live view.
For the IoT client, we set up alerts on the number of failures per minute. The day an edge device started sending malformed payloads, we were notified within 5 minutes. Before App Insights, that kind of issue took days to surface.
Key Vault: Never Put a Secret in appsettings.json Again
Every JADEV project uses Azure Key Vault for secrets. API keys, connection strings, tokens, everything goes through Key Vault.
The integration with Function Apps is native. You reference a secret in the app configuration using the `@Microsoft.KeyVault(SecretUri=...)` syntax and it's resolved at startup. No special code. No third-party library.
The real advantage is rotation. You change a secret in Key Vault, restart the app, done. No deployment. No commit with a plaintext password in the Git history (I've seen things...).
Azure vs AWS: Choose the Ecosystem
I get this question all the time. "Azure or AWS?" My answer is always the same.
Azure wins when your client is already on Microsoft 365. The integration with Entra ID (formerly Azure AD), licensing, SSO, it's seamless. You don't have to convince the IT director to open an account with another vendor.
AWS wins on raw Lambda performance. That's a fact. Cold starts are shorter, documentation is more mature on certain services.
But here's the thing: choose the ecosystem, not the benchmark. If your client uses Outlook, Teams, and SharePoint, Azure is the natural choice. If your client is a tech startup on Linux with developers who breathe Terraform, go with AWS.
The worst choice is mixing both for no reason. I've seen a project with auth on Azure, compute on AWS, and storage on GCP. The maintenance cost was absurd.
Mistakes I Wish I'd Avoided
A quick list, after dozens of deployments:
- Not enabling diagnostic logs from day one. When things break in prod, it's too late to turn them on.
- Use one storage account per Function App. It costs nothing and prevents lease blob collisions.
- Test cold starts before promising an SLA. On a consumption plan, the first call after 20 minutes of inactivity can take 5 to 10 seconds in .NET.
- Set a budget alert at €10 on every subscription. I once had an intern leave an AKS cluster running over a weekend. €180 for nothing.
Pragmatic Conclusion
Azure isn't perfect. The portal is slow, the documentation is sometimes inconsistent, and billing can surprise you if you're not watching.
But for a European SMB that wants to deploy APIs, async processing, or IoT workloads, it's a solid choice. The consumption plan lets you start with zero financial risk. The West Europe region settles the GDPR question. And the .NET isolated worker ecosystem is finally mature.
Start small. A contact form. A webhook. A file processing function. Measure the actual cost. Then decide whether to scale up.
That's how you build durable architectures. Not by reading whitepapers, but by shipping things that work.
