Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This reference covers how to develop Azure Functions using JavaScript and TypeScript with the @azure/functions npm package. For a general overview of Azure Functions concepts shared across all languages, see the Azure Functions developer reference.
| Resource | Link |
|---|---|
| Create your first JavaScript function | Visual Studio Code/CLI |
| Create your first TypeScript function | Visual Studio Code/CLI |
| Scenarios and samples | JavaScript/TypeScript |
| API reference | @azure/functions API |
Note
This article shows content for a specific programming model version based on the selector at the top of the page. The version you choose should match your @azure/functions npm package version. You can't mix v3 and v4 functions in the same app. If you don't have the package in your package.json, the default is v3.
Programming model
Azure Functions for Node.js supports two programming model versions. New projects should use v4.
| Feature | v4 (recommended) | v3 |
|---|---|---|
| Status | GA | GA (maintenance) |
@azure/functions package |
4.x | 3.x |
| Function registration | Code-centric (app.http(), app.timer()) |
File-based (function.json) |
| File structure | Flexible | Fixed (one folder per function) |
| Functions runtime version | 4.25+ | 4.x |
| Node.js versions | 24.x, 22.x | 24.x, 22.x |
In the Node.js v4 programming model, you register functions by importing the app object from @azure/functions and calling trigger-specific methods. The functions are defined directly in your code with a flexible file structure. Every function has a single trigger that starts its execution and can also have bindings, which are declarative connections to other services for reading input data or writing output data. For more information, see Triggers and bindings.
In the v4 model, you:
- Register functions by using trigger-specific methods like
app.http(),app.timer(), andapp.storageQueue(). - Access the trigger input as the first argument to your handler (for example,
HttpRequest). - Return the primary output directly from the handler function.
- Use
context.extraInputs.get()to read from extra input bindings like Blob Storage. - Use
context.extraOutputs.set()to write to extra output bindings like queues. - Each function has exactly one trigger, but can have multiple extra inputs and outputs.
- You can cache data in global variables for reuse across invocations, but don't rely on this state to persist. The runtime can recycle your worker at any time.
In the Node.js v3 programming model, you define each function by using a function.json configuration file and corresponding JavaScript or TypeScript code. You organize functions in separate folders with specific file structures. Every function has a single trigger that starts its execution and can also have bindings, which are declarative connections to other services for reading input data or writing output data. For more information, see Triggers and bindings.
In the v3 model, you:
- Define triggers and bindings in a
function.jsonfile. Usedirection: "in"for inputs anddirection: "out"for outputs. - Access the trigger input as the second argument to your handler, or read it from
context.bindings. - Set outputs by assigning values to
context.bindings(for example,context.bindings.outputQueue). For HTTP, usecontext.res. - TypeScript projects require a
scriptFileproperty infunction.jsonthat points to the compiled JavaScript file. - Each function has exactly one trigger, but can have multiple input and output bindings.
- You can cache data in global variables for reuse across invocations, but don't rely on this state to persist. The runtime can recycle your worker at any time.
Examples
Here's a simple function that responds to an HTTP request:
const { app } = require('@azure/functions');
app.http('httpTrigger', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: async (request, context) => {
const name = request.query.get('name') || 'World';
context.log('HTTP trigger function processed a request.');
return { body: `Hello, ${name}!` };
}
});
The following non-HTTP example uses a timer trigger:
const { app } = require('@azure/functions');
app.timer('cleanupTimer', {
schedule: '0 */5 * * * *',
handler: async (myTimer, context) => {
context.log('Timer trigger function ran at', new Date().toISOString());
}
});
The following example shows an HTTP trigger with a queue output binding:
const { app, output } = require('@azure/functions');
const queueOutput = output.storageQueue({
queueName: 'work-items',
connection: 'AzureWebJobsStorage'
});
app.http('submitWorkItem', {
methods: ['POST'],
extraOutputs: [queueOutput],
handler: async (request, context) => {
const body = await request.json();
context.extraOutputs.set(queueOutput, JSON.stringify(body));
return { status: 202, jsonBody: { accepted: true } };
}
});
Here's a simple function that responds to an HTTP request:
{
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": ["get", "post"]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
module.exports = async function (context, req) {
const name = (req.query.name || (req.body && req.body.name)) || 'World';
context.log('HTTP trigger function processed a request.');
context.res = {
body: `Hello, ${name}!`
};
};
The following non-HTTP example uses a timer trigger:
{
"bindings": [
{
"name": "myTimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 */5 * * * *"
}
]
}
module.exports = async function (context, myTimer) {
context.log('Timer trigger function ran at', new Date().toISOString());
};
The following example shows an HTTP trigger with a queue output binding:
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": ["post"]
},
{
"type": "queue",
"direction": "out",
"name": "workItems",
"queueName": "work-items",
"connection": "AzureWebJobsStorage"
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
module.exports = async function (context, req) {
const payload = req.body || {};
context.bindings.workItems = JSON.stringify(payload);
context.res = {
status: 202,
body: { accepted: true }
};
};
Building your function app
This section covers the essential components for creating and structuring your Node function app, including the @azure/functions library, project structure, and package management.
The @azure/functions library
The @azure/functions TypeScript/JavaScript library provides the core types and functions you use to interact with the Azure Functions runtime. To see all types and methods available, visit the @azure/functions API.
Your function code can use @azure/functions to:
- Register functions and define triggers (v4 model).
- Access strongly-typed trigger input data (for example,
HttpRequest,Timer). - Create typed output values (such as
HttpResponseInit). - Interact with runtime-provided context and binding data.
If you're using @azure/functions in your app, include it in your project dependencies:
{
"dependencies": {
"@azure/functions": "^4.0.0"
}
}
Note
The @azure/functions library defines the programming surface for Node.js Azure Functions, but it isn't a general-purpose SDK. Use it specifically for authoring and running functions within the Azure Functions runtime.
TypeScript configuration
For the best TypeScript development experience, ensure your tsconfig.json includes the proper configuration:
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "dist",
"rootDir": ".",
"sourceMap": true,
"strict": false,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
Folder structure
A JavaScript project requires the folder structure shown in the following example:
<project_root>/
| - .vscode/
| - node_modules/
| - myFirstFunction/
| | - index.js
| | - function.json
| - mySecondFunction/
| | - index.js
| | - function.json
| - .funcignore
| - host.json
| - local.settings.json
| - package.json
The main project folder, <project_root>, can contain the following files:
- .vscode/: (Optional) Contains the stored Visual Studio Code configuration. To learn more, see Visual Studio Code settings.
- myFirstFunction/function.json: Contains configuration for the function's trigger, inputs, and outputs. The name of the directory determines the name of your function.
- myFirstFunction/index.js: Stores your function code. To change this default file path, see using scriptFile.
- .funcignore: (Optional) Declares files that shouldn't get published to Azure. Usually, this file contains .vscode/ to ignore your editor setting, test/ to ignore test cases, and local.settings.json to prevent local app settings from being published.
- host.json: Contains configuration options that affect all functions in a function app instance. This file gets published to Azure. Not all options are supported when running locally. To learn more, see host.json.
- local.settings.json: Used to store app settings and connection strings when running locally. This file doesn't get published to Azure. To learn more, see local.settings.file.
- package.json: Contains configuration options like a list of package dependencies, the main entry point, and scripts.
A JavaScript project follows the recommended folder structure in the following example:
<project_root>/
| - .vscode/
| - node_modules/
| - src/
| | - functions/
| | | - myFirstFunction.js
| | | - mySecondFunction.js
| - test/
| | - functions/
| | | - myFirstFunction.test.js
| | | - mySecondFunction.test.js
| - .funcignore
| - host.json
| - local.settings.json
| - package.json
The main project folder, <project_root>, can contain the following files:
- .vscode/: (Optional) Contains the stored Visual Studio Code configuration. To learn more, see Visual Studio Code settings.
- src/functions/: The default location for all functions and their related triggers and bindings.
- test/: (Optional) Contains the test cases of your function app.
- .funcignore: (Optional) Declares files that shouldn't get published to Azure. Usually, this file contains .vscode/ to ignore your editor setting, test/ to ignore test cases, and local.settings.json to prevent local app settings from being published.
- host.json: Contains configuration options that affect all functions in a function app instance. This file gets published to Azure. Not all options are supported when running locally. To learn more, see host.json.
- local.settings.json: Used to store app settings and connection strings when running locally. This file doesn't get published to Azure. To learn more, see local.settings.file.
- package.json: Contains configuration options like a list of package dependencies, the main entry point, and scripts.
Package management
Effective package management is crucial for Node.js Azure Functions projects. This section covers dependency management, package configuration, and best practices for maintaining your function app dependencies.
Managing dependencies
All Node.js Azure Functions projects use npm for package management. Your package.json file defines the project configuration, dependencies, and scripts needed to build and run your functions.
Essential package.json structure:
{
"name": "my-functions-app",
"version": "1.0.0",
"description": "Azure Functions Node.js app",
"main": "src/index.js",
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"prestart": "npm run build",
"start": "func start",
"test": "jest"
},
"dependencies": {
"@azure/functions": "^4.0.0"
},
"devDependencies": {
"@azure/functions-core-tools": "^4.0.4670",
"@types/node": "^18.0.0",
"typescript": "^4.0.0",
"jest": "^29.0.0"
}
}
Runtime vs. development dependencies
Separate your dependencies appropriately:
Runtime dependencies (dependencies):
@azure/functions: The core Azure Functions library- Business logic libraries (lodash, axios, and similar packages)
- Database drivers (mongodb, mssql, and similar packages)
- Azure SDK packages (@azure/storage-blob, @azure/cosmos, and similar packages)
Development dependencies (devDependencies):
- TypeScript compiler and type definitions
- Testing frameworks (Jest, Mocha)
- Build tools and linters
- Azure Functions Core Tools (for local development)
TypeScript-specific packages
For TypeScript projects, include these essential development dependencies:
{
"devDependencies": {
"@types/node": "^18.0.0",
"typescript": "^4.0.0",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0"
}
}
Security and updates
Regularly update your dependencies to address security vulnerabilities:
# Check for outdated packages
npm outdated
# Update packages
npm update
# Audit for security issues
npm audit
npm audit fix
Running and debugging
This section covers local development, debugging techniques, and testing strategies for Node.js Azure Functions.
Local development setup
Prerequisites:
- Node.js version 18.x or 20.x
- Azure Functions Core Tools v4.x
- Azure CLI (optional)
Setup steps:
Install dependencies:
npm installBuild TypeScript projects:
npm run buildStart the local runtime:
npm start # or directly: func start
Environment configuration
Configure your local development environment by using local.settings.json:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "node",
"NODE_ENV": "development",
"CUSTOM_ENV_VARIABLE": "local-value"
},
"Host": {
"LocalHttpPort": 7071,
"CORS": "*",
"CORSCredentials": false
}
}
Debugging
Visual Studio Code debugging:
Create .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Node Functions",
"type": "node",
"request": "attach",
"port": 9229,
"preLaunchTask": "func: host start"
}
]
}
Create .vscode/tasks.json:
{
"version": "2.0.0",
"tasks": [
{
"type": "func",
"label": "func: host start",
"command": "host start",
"problemMatcher": "$func-node-watch",
"isBackground": true,
"options": {
"cwd": "${workspaceFolder}"
}
}
]
}
Command line debugging:
# Start with debugging enabled
func start --p <port>
# For TypeScript, ensure you build first
npm run build
func start --p 9229
Deployment
This section covers deployment strategies, CI/CD integration, and production best practices for Node.js Azure Functions.
Deployment methods
1. Visual Studio Code deployment:
- Install the Azure Functions extension.
- Right-click your function app in the Azure panel.
- Select Deploy to Function App.
2. Azure Functions Core Tools:
# Deploy to Azure
func azure functionapp publish <FunctionAppName>
# Deploy with custom settings
func azure functionapp publish <FunctionAppName> --build local --publish-local-settings
3. Azure CLI deployment:
# Deploy from local folder
az functionapp deployment source config-zip \
--resource-group <ResourceGroupName> \
--name <FunctionAppName> \
--src <PathToZipFile>
Production configuration
Application settings in Azure:
Configure environment variables for production:
WEBSITE_NODE_DEFAULT_VERSION: Set to~18or~20.FUNCTIONS_WORKER_RUNTIME: Set tonode.- Connection strings and API keys as secure app settings.
NODE_ENV: Set toproduction.
Triggers and bindings
Azure Functions uses triggers to start function execution and bindings to connect your code to other services like storage, queues, and databases. In the Node.js programming model, you declare bindings differently depending on your model version.
Two main types of bindings exist:
- Triggers (input that starts the function)
- Inputs and outputs (extra data sources or destinations)
For more information about the available triggers and bindings, see Triggers and Bindings in Azure Functions.
Example: Timer Trigger with Blob Input
This function triggers every 10 minutes, reads from a Blob using extra inputs, and logs the blob content.
const { app, input } = require('@azure/functions');
let CACHED_BLOB_DATA = null;
const blobInput = input.storageBlob({
connection: 'BLOB_CONNECTION_SETTING',
path: 'mycontainer/myblob.txt'
});
app.timer('TimerTriggerWithBlob', {
schedule: '0 */10 * * * *',
extraInputs: [blobInput],
handler: async (myTimer, context) => {
if (CACHED_BLOB_DATA === null) {
// Read blob content and cache it
CACHED_BLOB_DATA = context.extraInputs.get(blobInput);
context.log(`Blob content cached: ${CACHED_BLOB_DATA?.substring(0, 100)}...`);
}
context.log(`Timer function executed at: ${new Date().toISOString()}`);
context.log(`Using cached data of length: ${CACHED_BLOB_DATA?.length || 0}`);
}
});
This function triggers every 10 minutes, reads from a Blob by using bindings configuration, and logs the blob content.
{
"scriptFile": "index.js",
"bindings": [
{
"name": "myTimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 */10 * * * *"
},
{
"name": "blobInput",
"type": "blob",
"direction": "in",
"path": "mycontainer/myblob.txt",
"connection": "AzureWebJobsStorage"
}
]
}
let CACHED_BLOB_DATA = null;
module.exports = async function (context, myTimer) {
if (CACHED_BLOB_DATA === null) {
// Read blob content and cache it
CACHED_BLOB_DATA = context.bindings.blobInput;
context.log(`Blob content cached: ${CACHED_BLOB_DATA?.substring(0, 100)}...`);
}
context.log(`Timer function executed at: ${new Date().toISOString()}`);
context.log(`Using cached data of length: ${CACHED_BLOB_DATA?.length || 0}`);
};