Skip to content

Instantly share code, notes, and snippets.

@gunzip
Last active February 19, 2026 08:02
Show Gist options
  • Select an option

  • Save gunzip/d5c972ce5cb62bc4ec39c466a66dc0c9 to your computer and use it in GitHub Desktop.

Select an option

Save gunzip/d5c972ce5cb62bc4ec39c466a66dc0c9 to your computer and use it in GitHub Desktop.
name description license
azure-functions-v4-migration
Migrate Azure Functions from the deprecated Node.js v3 model to the new v4 model. Use when asked to upgrade Azure Functions, migrate to v4 model, or refactor function handlers to follow the latest standards.
Complete terms in LICENSE.txt

Azure Functions v4 Migration Skill

This skill provides the instructions and patterns required to migrate PagoPA Azure Functions from the deprecated Node.js v3 model to the new v4 model using the wrapHandlerV4 adapter from @pagopa/io-functions-commons.

When to Use This Skill

  • When upgrading a project's Azure Functions model from v3 to v4.
  • When refactoring existing handlers to use the standardized wrapHandlerV4 approach.
  • When creating new Azure Functions that should follow the v4 model.

Prerequisites

  • @azure/functions version ^4.0.0
  • @pagopa/io-functions-commons version ^30.0.0
  • TypeScript project setup.

Step-by-Step Workflows

1. Update package.json

Update the dependencies and add the main entry point.

Field Action Value
main Add/Update dist/main.js
@azure/functions Update ^4.0.0
@pagopa/io-functions-commons Update ^30.0.0
@pagopa/express-azure-functions Remove (No longer needed)
express Remove (If only used for v3 adapter)

2. Remove Deprecated Files

The v4 model uses a code-first approach for registration.

  • Remove all function.json files in function directories.
  • Remove index.ts files that served as v3 entry points.
  • Remove winston-related logging boilerplate (e.g., AzureContextTransport setup) as v4 handles logging natively through InvocationContext.

3. Create/Update Entry Point (main.ts)

Create a centralized src/main.ts to register all HTTP functions.

import { app } from "@azure/functions";
import { Info } from "./Info/handler";
// Import other handlers...

app.http("Info", {
  methods: ["GET"],
  authLevel: "anonymous", // or "function"
  route: "info",
  handler: Info(),
});

// Register other functions...

4. Refactor Handlers

Replace v3 wrapping logic with wrapHandlerV4.

Pattern Changes

Feature v3 (Old) v4 (New)
Wrapper wrapRequestHandler(handler) wrapHandlerV4(middlewares, handler)
Import @pagopa/io-functions-commons/dist/src/utils/request_middleware @pagopa/io-functions-commons/dist/src/utils/azure-functions-v4-express-adapter
Context Context InvocationContext
Error Log context.log.error context.error
Debug Log context.log.verbose context.debug
Warning Log context.log.warn context.warn
Info Log context.log.info context.log

Handler Signature

In v4, the handler receives the InvocationContext as the first argument, followed by the resolved values of the middlewares in the order they are defined in the middlewares array.

  • Note: ContextMiddleware() result is typically the context itself and is often skipped or merged in the handler signature if it's the first middleware.
type IMyHandler = (
  context: InvocationContext,
  token: TokenParam, // First middleware after ContextMiddleware
) => Promise<IResponse...>;

Middleware Refactoring

Standardize middlewares using built-in factories from @pagopa/io-functions-commons where possible:

// Old custom middleware
export const TokenHeaderParamMiddleware = async (request: Request) => ...

// New standardized middleware
export const TokenHeaderParamMiddleware = RequiredHeaderMiddleware(
  TOKEN_HEADER_NAME,
  TokenParam,
);

Example Implementation

import { wrapHandlerV4 } from "@pagopa/io-functions-commons/dist/src/utils/azure-functions-v4-express-adapter";
import { ContextMiddleware } from "@pagopa/io-functions-commons/dist/src/utils/middlewares/context_middleware";

export const MyFunction = () => {
  const handler = MyFunctionHandler();

  const middlewares = [
    ContextMiddleware(),
    // Add other middlewares here
  ] as const;

  return wrapHandlerV4(middlewares, handler);
};

5. Update Middlewares

Ensure middlewares are compatible with the v4 adapter. Many PagoPA-standard middlewares already work, but some may need to be updated to return the expected Promise<Either<...>> format if they were using custom Express-style logic.

6. Update Tests

Update unit tests to accommodate the new InvocationContext and handler signature.

  • Change Context mocks to InvocationContext.
  • Update property accesses (log.error to error).
  • v4 handlers are invoked as handler(context, ...args) where args are the resolved middleware results.

Troubleshooting

Issue Solution
Functions not discovered Ensure main in package.json points to the compiled main.js.
Middleware type mismatch Ensure middlewares are passed as a const array to wrapHandlerV4 to preserve type inference.
Missing context in handler Ensure ContextMiddleware() is included in the middlewares array.
Build errors with express Remove express and @types/express if they are no longer explicitly used outside of the adapter.

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment