Azure Functions
The Azure adapter plugs a DaloyJS app into one catch-all HTTP trigger of the Azure Functions Node.js v4 programming model. The v4 HttpRequest looks like a web Request but is not one, and the host expects an HttpResponseInit object back, so toAzureHandler(app) converts both directions. Routing, validation, and errors all stay in DaloyJS.
- platformHTTP triggerroute: {*path} · HttpRequest
- adaptertoAzureHandler(app)body stream in · cookies out
- coreapp.fetch(Request)routing · hooks · handler
- platformHttpResponseInitstatus · headers · cookies · body
When to choose Azure Functions
- Your organisation already runs on Azure and wants per-request billing with Entra ID, Key Vault, and VNet integration close by.
- You want a serverless REST API next to Azure Storage, Service Bus, or Cosmos DB triggers in the same Function App.
- You need the Flex Consumption or Premium plans for VNet access or always-ready instances.
Install
The adapter ships with @daloyjs/core and needs no Azure types at runtime. Your Function App still installs the Azure runtime package:
Use a Node.js version that Azure Functions supports and DaloyJS requires (Node 24 LTS or newer). Check the Azure Functions supported-languages table for your plan before you deploy.
Register one catch-all trigger
Azure prefixes HTTP routes with /api by default. Set the prefix to empty so your DaloyJS routes keep their own paths:
If you keep the /api prefix instead, mount your routes under /api in the app.
Streaming responses
By default the Functions host buffers the whole response. For Server-Sent Events, NDJSON, or large downloads, turn on HTTP streams in the host and tell the adapter to hand the body over as a stream:
Set both together. stream: true without enableHttpStream still works, but Azure buffers the stream anyway.
Auth level
authLevel: "anonymous" means Azure does not check a function key, and DaloyJS route auth (bearerAuth(), jwk(), sessions) is the gate. Use authLevel: "function" only as an extra outer key check, for example for an internal API called by another service. A function key is a shared secret, not user identity, so it does not replace route-level auth.
Client IP
Azure does not expose the TCP peer to the handler, so getConnInfo(ctx.request) is undefined on Azure. The platform front end forwards the caller in X-Forwarded-For instead. Declare the proxy posture so rateLimit() and resolveClientIp() read the right entry:
What the adapter does for you
- Body limits. The request body is passed in as the host's stream, so
bodyLimitBytesis enforced while the body is read. An oversized body gets413. - Cookies. The Functions host keeps one value per header name, so the adapter moves every
Set-Cookieonto thecookiesarray of the response.PartitionedandPriorityhave no Azure field and are dropped. A malformedSet-Cookiewithoutname=valueis left out. - Bad requests. A request URL that cannot be parsed is answered with a
400problem+json, never an unhandled exception. - Telemetry. OTLP data is flushed before the handler returns, because a scaled-in instance gets no shutdown hook.
Gotchas
- Shutdown hooks (
app.onShutdown,app.onClose) are not wired on Azure: the platform owns the process lifecycle, so do not rely on them for flushing state. GETandHEADbodies are ignored, the same as a webRequest.- Only the v4 programming model is supported. The older v3 model (
context.res,function.jsonper function) has a different handler shape; migrate the Function App to v4 first.
See also
- Adapters overview
- AWS Lambda: the same buffered-or-streamed choice on AWS.
- Reverse proxy and client IPs · Boot guards