Waqas Ahmad — Software Architect & Technical Consultant - Available USA, Europe, Global

Waqas Ahmad — Software Architect & Technical Consultant

Specializing in

Distributed Systems

.NET ArchitectureCloud-Native ArchitectureAzure Cloud EngineeringAPI ArchitectureMicroservices ArchitectureEvent-Driven ArchitectureDatabase Design & Optimization

👋 Hi, I'm Waqas — a Software Architect and Technical Consultant specializing in .NET, Azure, microservices, and API-first system design..
I help companies build reliable, maintainable, and high-performance backend platforms that scale.

Experienced across engineering ecosystems shaped by Microsoft, the Cloud Native Computing Foundation, and the Apache Software Foundation.

Available for remote consulting (USA, Europe, Global) — flexible across EST, PST, GMT & CET.

services
Article

Azure Serverless: Functions and Logic Apps In-Depth

Azure Functions and Logic Apps: when to use which, triggers, and bindings.

services
Read the article

Introduction

This guidance is relevant when the topic of this article applies to your system or design choices; it breaks down when constraints or context differ. I’ve applied it in real projects and refined the takeaways over time (as of 2026).

Serverless on Azure lets you run code or workflows without managing servers, but choosing between Azure Functions (code-first) and Logic Apps (low-code) affects how you build and maintain integrations. This article explains what each is, when to use which, triggers and bindings, pricing, and enterprise best practices so you can choose and build serverless solutions on Azure. Getting the split right matters for architects and tech leads who need to ship event-driven and integration workloads without over-building in code or under-building in low-code.

For a deeper overview of this topic, explore the full Cloud-Native Architecture guide.

Decision Context

  • System scale: Event-driven workloads, integrations, or APIs that can scale to zero or burst; from a few functions to many. Applies when you want to avoid managing VMs and pay per execution.
  • Team size: One developer to a platform team; someone must own function apps, Logic App definitions, and connections. Works when devs can own code-first (Functions) or when integration owners can own low-code (Logic Apps).
  • Time / budget pressure: Fits greenfield serverless and “quick integration” needs; breaks down when you need long-running processes (use containers or Durable) or strict compliance that forbids shared multi-tenant compute.
  • Technical constraints: Azure as the target cloud; .NET, Node, or other supported runtimes for Functions; Logic Apps for connector-heavy workflows. Assumes you can use Key Vault and managed identity.
  • Non-goals: This article does not optimise for AWS Lambda, Google Cloud Functions, or on-prem; it focuses on Azure Functions and Logic Apps and when to use which.

What is serverless?

Serverless does not mean “no servers”—it means you do not manage them. The cloud provider:

  • Allocates compute on demand
  • Scales automatically (including to zero)
  • Charges per execution, not per hour
Benefit Description
No infrastructure No VMs to patch or scale
Auto-scale Handles spikes automatically
Pay per use No cost when idle
Fast deployment Deploy functions in seconds

Azure Functions overview

Azure Functions is a code-first serverless compute service. You write functions in C#, JavaScript, Python, Java, or PowerShell. Functions run in response to triggers (HTTP, timer, queue, blob, etc.).

Key concepts:

  • Function App: Container for one or more functions
  • Trigger: What starts the function (HTTP request, message, timer)
  • Binding: Declarative connection to data (input/output)
  • Host: Runtime that executes functions

Hosting plans:

Plan Scaling Cold start Use case
Consumption Auto (0 to many) Yes Event-driven, variable load
Premium Auto (1+ warm) Minimal Low latency, VNet
Dedicated Manual/auto No Existing App Service

Azure Logic Apps overview

Logic Apps is a low-code/no-code workflow service. You build workflows visually using a designer with 400+ connectors (Office 365, Salesforce, SAP, etc.).

Key concepts:

  • Workflow: Series of steps triggered by an event
  • Trigger: What starts the workflow
  • Action: Each step in the workflow
  • Connector: Pre-built integration (e.g. SQL, Blob, HTTP)

Use cases:

  • Integration between SaaS apps
  • Business process automation
  • File processing and transformation
  • Approval workflows

Functions vs Logic Apps

Aspect Azure Functions Logic Apps
Approach Code-first Low-code/visual
Language C#, JS, Python, Java Visual designer
Best for Custom logic, compute Integration, workflows
Connectors Bindings (limited) 400+ connectors
State Stateless (or Durable) Stateful by default
Debugging Local + remote Portal + run history
Pricing Per execution Per action/connector

When to use Functions:

  • Custom compute logic
  • High-performance processing
  • Fine-grained control over code
  • Team prefers code over visual

When to use Logic Apps:

  • Integration between systems
  • Workflows with approvals
  • Connecting SaaS apps
  • Citizen developers / low-code

Triggers and bindings

Function triggers

Trigger Fires when
HTTP HTTP request received
Timer Schedule (CRON expression)
Queue Message added to Storage Queue or Service Bus
Blob Blob created/updated
Event Grid Event Grid event
Cosmos DB Document changed

Bindings (input/output)

Bindings let functions read/write data without boilerplate:

// Input binding: read from Cosmos DB
// Output binding: write to Queue
[FunctionName("ProcessOrder")]
public static async Task Run(
    [HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req,
    [CosmosDB("orders", "items", Connection = "CosmosConnection", Id = "{orderId}")] Order order,
    [Queue("processed-orders")] IAsyncCollector<string> outputQueue,
    ILogger log)
{
    log.LogInformation("Processing order {OrderId}", order.Id);
    await outputQueue.AddAsync(order.Id);
}

Azure Functions code examples

HTTP trigger (C#)

[FunctionName("GetOrder")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Function, "get", Route = "orders/{id}")] HttpRequest req,
    string id,
    [CosmosDB("orders", "items", Connection = "CosmosConnection", Id = "{id}", PartitionKey = "{id}")] Order order,
    ILogger log)
{
    if (order == null)
    {
        return new NotFoundResult();
    }
    
    return new OkObjectResult(order);
}

Timer trigger (scheduled job)

[FunctionName("DailyCleanup")]
public static async Task Run(
    [TimerTrigger("0 0 2 * * *")] TimerInfo timer, // 2 AM daily
    [CosmosDB("orders", "items", Connection = "CosmosConnection")] IAsyncCollector<Order> orders,
    ILogger log)
{
    log.LogInformation("Running daily cleanup at {Time}", DateTime.UtcNow);
    // Cleanup logic here
}

Queue trigger (message processing)

[FunctionName("ProcessMessage")]
public static async Task Run(
    [ServiceBusTrigger("orders", Connection = "ServiceBusConnection")] string message,
    [CosmosDB("orders", "processed", Connection = "CosmosConnection")] IAsyncCollector<ProcessedOrder> output,
    ILogger log)
{
    var order = JsonSerializer.Deserialize<Order>(message);
    log.LogInformation("Processing order {OrderId}", order.Id);
    
    await output.AddAsync(new ProcessedOrder
    {
        Id = order.Id,
        ProcessedAt = DateTime.UtcNow
    });
}

Durable Functions

Durable Functions extend Azure Functions for stateful workflows. They handle:

  • Long-running orchestrations
  • Fan-out/fan-in patterns
  • Human interaction (wait for approval)
  • Chaining functions
// Orchestrator function
[FunctionName("OrderOrchestrator")]
public static async Task<string> RunOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var orderId = context.GetInput<string>();
    
    // Chain activities
    await context.CallActivityAsync("ValidateOrder", orderId);
    await context.CallActivityAsync("ProcessPayment", orderId);
    await context.CallActivityAsync("ShipOrder", orderId);
    
    return "Order completed";
}

// Activity function
[FunctionName("ValidateOrder")]
public static async Task ValidateOrder(
    [ActivityTrigger] string orderId,
    ILogger log)
{
    log.LogInformation("Validating order {OrderId}", orderId);
    // Validation logic
}

Logic Apps workflows

Example: Process uploaded files

  1. Trigger: When a blob is added to Storage
  2. Action: Get blob content
  3. Action: Parse JSON
  4. Action: Insert into SQL Database
  5. Action: Send email notification

Example: Approval workflow

  1. Trigger: HTTP request (new expense report)
  2. Action: Send approval email (Office 365)
  3. Action: Wait for response
  4. Condition: If approved → Insert to database
  5. Condition: If rejected → Send rejection email

Logic Apps handles retry, state, and connectors automatically.

Pricing

Azure Functions

Plan Cost
Consumption Free: 1M executions/month, 400K GB-s. Then pay per execution
Premium Per vCPU-hour + memory
Dedicated App Service pricing

Logic Apps

Plan Cost
Consumption Per action execution + connector calls
Standard Per workflow + vCPU-hour

Tip: Functions Consumption is very cheap for low-to-medium volume. Logic Apps can get expensive with many actions or premium connectors.

Enterprise best practices

1. Use Managed Identity. No secrets in code. Functions and Logic Apps can authenticate to Key Vault, Storage, SQL, etc.

2. Store secrets in Key Vault. Reference secrets from configuration, not app settings.

3. Use Application Insights. Monitor executions, failures, and latency. Set alerts.

4. Handle failures. Use retry policies, dead-letter queues, and compensation logic.

5. Limit cold starts. For latency-sensitive workloads, use Premium plan or keep-warm pings.

6. Use VNet integration. For private resources, use Premium Functions or Logic Apps Standard with VNet.

7. Version and test. Use slots for staging. Test Functions locally before deploying.

8. Right-size. Monitor execution time and memory. Optimize for cost.

Common issues

Issue Cause Fix
Cold start latency Consumption plan spins up Use Premium or keep-warm
Timeout Function exceeds limit Increase timeout; use Durable for long tasks
Connector throttling Logic Apps hits API limits Add delays; use batching
Secret exposure Secrets in app settings Use Key Vault references
Cost spike Unexpected volume Set budget alerts; review executions
Debugging difficulty No local Logic Apps Use run history; consider Functions

You can also explore more patterns in the Cloud-Native Architecture resource page.

Summary

Azure Functions is for code-first serverless compute; Logic Apps is for low-code integration workflows—use Functions for custom logic and performance, Logic Apps for connecting systems and business processes; both auto-scale and charge per use. Picking the wrong one leads to hard-to-maintain Logic Apps or over-engineered Functions; matching the tool to the workload keeps delivery fast and ops simple. Next, map your triggers and integration points, then choose Functions, Logic Apps, or a hybrid (e.g. Logic App calls a Function) and document the split so the team knows where to add new logic.

Position & Rationale

I use Functions when the workload is code-heavy, latency-sensitive, or needs full control (e.g. custom .NET, complex logic, Durable orchestration). I use Logic Apps when the workload is connector-heavy and the team prefers visual workflows (e.g. “when email arrives, parse, call API, write to SQL”). I avoid using Logic Apps for complex branching and transformation that would be clearer in code—that’s where I switch to Functions or a hybrid (Logic App calls a Function). I also avoid Functions for “glue” that is purely “trigger → call connector → call connector” with no real logic; Logic Apps is faster to build and maintain there. Durable Functions I reserve for multi-step, long-running, or human-in-the-loop flows that need state; for simple fire-and-forget or request–response, a single Function is enough.

Trade-Offs & Failure Modes

Functions sacrifice the low-code speed of Logic Apps and require code deployment and testing; cold starts (Consumption) can hurt latency. Logic Apps sacrifice fine-grained control and debuggability; complex logic in the designer becomes hard to maintain. Hybrid (Logic App + Function) adds another moving part but can be the right split. Failure modes: putting all logic in Logic Apps and hitting connector limits or unreadable workflows; putting all logic in Functions and reinventing connectors; ignoring cold start and then complaining about latency; storing secrets in app settings instead of Key Vault.

What Most Guides Miss

Most guides compare “Functions vs Logic Apps” on features but don’t stress that the real decision is trigger + integration vs custom code. If the bulk of the work is “call this API, then that one, then persist,” Logic Apps is often faster. If the bulk is “parse this, validate, transform, apply business rules,” Functions is clearer. Another gap: Durable Functions are underused—teams build ad-hoc state in queues or databases when an orchestration would be simpler. Finally, cost is often presented as “per execution”; in practice, connector calls in Logic Apps and execution time in Functions both matter—high-volume or long-running Logic Apps can get expensive.

Decision Framework

  • If the workload is mostly “connect A to B to C” with minimal logic → Prefer Logic Apps; use connectors and the designer.
  • If the workload is custom logic, parsing, or performance-sensitive code → Prefer Functions (and Durable if multi-step or long-running).
  • If you need both → Use Logic App as the trigger/orchestrator and call a Function for the heavy logic.
  • If cold start is a problem → Use Premium plan or keep-warm; avoid Consumption for user-facing HTTP.
  • For secrets and identity → Use Key Vault references and managed identity on both.

Key Takeaways

  • Functions = code-first, custom logic, performance, Durable for orchestration. Logic Apps = low-code, connectors, integration workflows.
  • Choose by workload: connector-heavy and visual → Logic Apps; code-heavy and control → Functions.
  • Use Durable Functions when you need stateful, long-running, or human-in-the-loop flows.
  • Cold start matters on Consumption; use Premium or keep-warm for latency-sensitive HTTP.
  • Use Key Vault and managed identity; don’t store secrets in app settings.

When I Would Use This Again — and When I Wouldn’t

I’d use Azure Functions again for APIs, event handlers, and any custom .NET logic that needs to scale with demand; and Durable Functions for multi-step or long-running workflows. I’d use Logic Apps again for integration-heavy flows (e.g. “on new blob, transform, send to CRM”) where the team is comfortable with the designer. I wouldn’t use Logic Apps for complex branching and transformation that belongs in code, and I wouldn’t use Functions for simple “trigger → two connectors” flows where Logic Apps would be faster to build and change.

For production-grade Azure systems, I offer consulting on cloud architecture, scalability, and cloud-native platform design.

services
Frequently Asked Questions

Frequently Asked Questions

What is serverless?

Serverless means the cloud provider manages infrastructure. You write code or workflows; Azure handles scaling, patching, and billing per use.

What is Azure Functions?

Azure Functions is a code-first serverless compute service. Write functions in C#, JS, Python; they run in response to triggers (HTTP, queue, timer).

What is Logic Apps?

Logic Apps is a low-code workflow service with 400+ connectors. Build integrations visually without writing code.

When should I use Functions vs Logic Apps?

Use Functions for custom compute logic and performance. Use Logic Apps for integration workflows and connecting SaaS apps.

What is a trigger?

A trigger is what starts a function or workflow—HTTP request, message, timer, blob, event.

What are bindings?

Bindings are declarative connections to data. Input bindings read; output bindings write. No boilerplate code.

What is Durable Functions?

Durable Functions extend Functions for stateful workflows: orchestration, fan-out/fan-in, human interaction.

How do I handle cold starts?

Cold starts occur in Consumption plan. Use Premium plan for warm instances, or use keep-warm pings.

How do I secure Functions?

Use Managed Identity for Azure resources. Store secrets in Key Vault. Use function keys or Azure AD for HTTP triggers.

How much do Functions cost?

Consumption: 1M free executions/month, then ~$0.20 per million. Premium and Dedicated have different pricing.

How do I debug Logic Apps?

Use the run history in the portal. Each run shows inputs/outputs for every action. Use tracked properties for custom logging.

Can Functions call Logic Apps?

Yes. Use HTTP trigger on Logic Apps; call from Functions via HttpClient.

What connectors does Logic Apps have?

400+ connectors: Office 365, SQL, Blob, Service Bus, Salesforce, SAP, Twitter, etc.

How do I deploy Functions?

Use Azure CLI, VS Code, GitHub Actions, or Azure DevOps. Zip deploy or run from package.

Can I run Functions locally?

Yes. Use Azure Functions Core Tools. Run and debug locally before deploying.

services
Related Guides & Resources

services
Related services