Why Serverless GraphQL Matters
Imagine a mobile app that needs to fetch user profiles, order history, and real‑time notifications—all in a single request. Traditional REST endpoints would require multiple round‑trips, inflating latency and consuming more bandwidth. GraphQL consolidates those calls, and when paired with a serverless platform like Azure Functions, you pay only for the compute you actually use, while Dapr adds reliable event‑driven capabilities. According to the 2023 State of Serverless report, 68% of enterprises cite reduced operational cost as the primary driver for adopting serverless architectures.
Setting Up a .NET 8 Azure Functions Project
Start with the .NET 8 SDK (released November 2023) and the Azure Functions Core Tools version 4.0 or later. The minimal system requirements are a Windows 10/11, macOS 12+, or a recent Linux distribution with Docker support.
Open a terminal and run the following commands:
dotnet new tool-manifest # optional, creates a local tool manifest
dotnet tool install -g azure-functions-core-tools@4
dotnet new func -n GraphqlServerless --worker-runtime dotnetIsolated --target-framework net8.0The template generates a FunctionApp project that uses the isolated worker model, which is required for .NET 8 features like native AOT compilation.
Integrating Dapr for Event‑Driven Architecture
Dapr (Distributed Application Runtime) abstracts pub/sub, state stores, and bindings behind a simple HTTP or gRPC API. Adding Dapr to an Azure Function is as easy as decorating the method with the DaprTopic attribute.
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Dapr;
public class OrderEvents
{
[Function("OrderCreated")]
[DaprTopic("pubsub", "order-created")]
public async Task<HttpResponseData> RunAsync(
[DaprBindingTrigger] OrderCreatedEvent order,
FunctionContext context)
{
var logger = context.GetLogger("OrderCreated");
logger.LogInformation($"Received order {order.OrderId} for {order.Amount:C}");
// Persist to a state store or trigger further GraphQL mutations
var response = context.GetHttpResponseData(HttpStatusCode.OK);
await response.WriteStringAsync("Processed");
return response;
}
}Deploy the function with az functionapp create and enable the Dapr sidecar by adding --enable-dapr to the deployment command. Azure Functions automatically injects the Dapr HTTP endpoint at http://localhost:3500 during local debugging.
Defining a GraphQL Schema with HotChocolate
HotChocolate is the de‑facto GraphQL server library for .NET. In the Program.cs file, register the schema and bind it to the Azure Function HTTP trigger.
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using HotChocolate;
using HotChocolate.Execution;
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(s =>
{
s.AddGraphQLServer()
.AddQueryType()
.AddMutationType();
})
.Build();
await host.RunAsync(); The Query and Mutation classes encapsulate business logic. For example:
public class Query
{
public async Task<User> GetUserAsync(string id,
[Service] IUserRepository repo) => await repo.GetByIdAsync(id);
}
public class Mutation
{
public async Task<Order> CreateOrderAsync(CreateOrderInput input,
[Service] IOrderService service)
{
var order = await service.CreateAsync(input);
// Publish an event for Dapr subscribers
await service.PublishOrderCreatedAsync(order);
return order;
}
}Because the function runs in an isolated process, the GraphQL endpoint can be exposed via a single HTTP trigger that forwards the request to HotChocolate’s request executor.
Performance Tips and Scaling Strategies
Azure Functions automatically scales out based on incoming request volume, but you can fine‑tune the behavior. Set the functionTimeout to 00:05:00 for long‑running queries, and enable pre‑warm for premium plans to keep cold‑starts under 200 ms. In .NET 8, enable native AOT for the function app to reduce startup time by up to 40%.
Combine Dapr’s pub/sub with Azure Service Bus for guaranteed delivery. Configure the pubsub component JSON:
{
"apiVersion": "dapr.io/v1alpha1",
"kind": "Component",
"metadata": {"name": "pubsub", "namespace": "default"},
"spec": {
"type": "bindings.azure.servicebus",
"version": "v1",
"metadata": {
"connectionString": "Endpoint=sb://myservicebus.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=***"
}
}
}By decoupling write‑through mutations from read‑through queries, you can handle spikes of up to 10,000 requests per second without overloading the database.
Testing Locally and Deploying to Azure
Run the function locally with Dapr using Docker Compose:
version: "3.8"
services:
function:
image: mcr.microsoft.com/azure-functions/dotnet-isolated:4
build: .
ports:
- "7071:80"
environment:
- AzureWebJobsStorage=UseDevelopmentStorage=true
depends_on:
- dapr
dapr:
image: daprio/daprd:latest
command: ["./daprd", "-app-id", "graphql-func", "-app-port", "80", "-components-path", "/components"]
volumes:
- ./components:/componentsAfter verifying that http://localhost:7071/api/graphql returns the GraphQL Playground, publish with the Azure CLI:
az group create --name rg-graphql --location eastus
az storage account create --name stgraphql --resource-group rg-graphql --sku Standard_LRS
az functionapp create --resource-group rg-graphql --consumption-plan-location eastus --runtime dotnet-isolated --functions-version 4 --name func-graphql --storage-account stgraphql --enable-dapr trueThe --enable-dapr flag provisions the sidecar automatically. Set the WEBSITE_DAPR_APP_ID application setting to graphql-func so the function can locate the Dapr HTTP endpoint.
Conclusion
Combining .NET 8, Azure Functions, and Dapr gives you a truly serverless GraphQL platform that scales on demand, stays cost‑effective, and embraces event‑driven patterns. By leveraging HotChocolate for schema definition, Dapr for reliable pub/sub, and Azure’s built‑in scaling, developers can deliver sub‑second response times even under heavy load. The practical steps outlined above—project scaffolding, Dapr integration, schema creation, performance tuning, and deployment—provide a repeatable blueprint for production‑grade APIs.
Author: Mahmut Sarıkaya — sarikayadev.com
Sources
Microsoft Docs – Azure Functions documentation
HotChocolate GraphQL for .NET official guide
Dapr.io – Pub/Sub component reference