Introduction
Azure App Service is a fully managed PaaS platform from Microsoft for hosting web apps, APIs, and static sites without managing the underlying infrastructure. In 2026, it natively integrates AI for intelligent auto-scaling and advanced diagnostics via Azure Monitor. This intermediate tutorial guides you through deploying a complete Node.js API: from creating the service to production rollout with deployment slots and horizontal scaling.
Why does this matter? App Service cuts time-to-market by 70% compared to manual VMs, auto-handles SSL certificates, and scales automatically under load. Imagine your app handling 10 to 10k users without any intervention—that's the norm with App Service. We use Azure CLI for CI/CD automation, a hands-on Node.js app with Express, and advanced configs. By the end, you'll have a production-ready, monitored, and scalable stack.
Prerequisites
- Active Azure account (free credits via azure.microsoft.com/free)
- Azure CLI 2.65+ installed (docs.microsoft.com/cli/azure/install-azure-cli)
- Node.js 20+ and npm
- Git installed
- Basic knowledge of Node.js and Azure (intermediate level)
Log in to Azure CLI
az login
az account set --subscription "Votre Subscription ID"
az extension add --name webapp --upgradeThis command logs you into your Azure account and sets the active subscription. The webapp extension adds App Service-specific commands. Verify with az --version; pitfall: skipping az login causes silent deployment failures.
Create Resource Group and App Service Plan
A resource group bundles all related Azure assets (like a project folder). The App Service plan defines resources (CPU, RAM, region) and pricing tier (Free, Basic, Premium v3 for scaling).
Create RG and App Service Plan
az group create --name rg-appservice-tutorial --location "westeurope"
az appservice plan create --name plan-appservice-tutorial --resource-group rg-appservice-tutorial --sku P1V3 --is-linuxCreates a resource group in West Europe and a Premium v3 Linux plan (scales to 30 instances). --is-linux optimizes for Node.js. Pitfall: Free tier limits CPU to 60 min/day; upgrade for production high availability.
Create the App Service
az webapp create --resource-group rg-appservice-tutorial --plan plan-appservice-tutorial --name monapp-nodejs-2026 --runtime "NODE|20-lts" --deployment-local-gitCreates an empty app with Node 20 LTS runtime and enables local Git for direct pushes. Replace monapp-nodejs-2026 with a globally unique name. Final URL: https://monapp-nodejs-2026.azurewebsites.net. Pitfall: name taken = error; add a timestamp.
Prepare the Node.js Application
Create a local Node.js project with Express for a simple REST API. We include health checks and logging for Azure diagnostics.
Complete package.json
{
"name": "api-nodejs-appservice",
"version": "1.0.0",
"description": "API pour Azure App Service",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
},
"dependencies": {
"express": "^4.19.2"
},
"engines": {
"node": "20.x"
}
}Declares the required start script (mandatory for App Service) and locks Node to 20.x via engines. Run npm install afterward. Pitfall: no start script causes app crashes; Azure runs npm start on boot.
Complete Express Server
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
app.use(express.json());
app.get('/health', (req, res) => {
res.json({ status: 'OK', timestamp: new Date().toISOString() });
});
app.get('/api/users', (req, res) => {
res.json([{ id: 1, name: 'User1' }, { id: 2, name: 'User2' }]);
});
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
module.exports = app;Basic API with /health endpoint (for Azure liveness probes) and /api/users. process.env.PORT is mandatory (Azure assigns dynamically). Pitfall: hardcoding port 3000 causes 230s timeouts and crashes.
Initialize Git and Deploy
git init
git add .
git commit -m "Initial commit"
az webapp deployment source config-local-git --name monapp-nodejs-2026 --resource-group rg-appservice-tutorial
git remote add azure $(az webapp deployment source show --name monapp-nodejs-2026 --resource-group rg-appservice-tutorial --query url --output tsv)
git push azure mainInitializes Git, configures Git deployment, and pushes to Azure (auto-builds with npm install). App goes live in <1 min. Pitfall: missing --query url sets wrong remote; check logs with az webapp log tail.
Advanced Configuration: Environment Variables
In production, store secrets in App Settings (encrypted and injected as env vars).
Add Env Vars and HTTPS Config
az webapp config appsettings set --resource-group rg-appservice-tutorial --name monapp-nodejs-2026 --settings WEBSITE_NODE_DEFAULT_VERSION="20-lts" API_KEY="supersecret"
az webapp update --resource-group rg-appservice-tutorial --name monapp-nodejs-2026 --https-only trueSets API_KEY accessible via process.env.API_KEY in code. Forces HTTPS (free). Pitfall: auto-restart; test with curl https://monapp-nodejs-2026.azurewebsites.net/health.
Horizontal Scaling and Staging Slot
az appservice plan update --name plan-appservice-tutorial --resource-group rg-appservice-tutorial --number-of-workers 3 --sku P2V3
az webapp deployment slot create --name monapp-nodejs-2026 --resource-group rg-appservice-tutorial --slot staging
az webapp deployment source config --name monapp-nodejs-2026 --resource-group rg-appservice-tutorial --slot staging --remote-url $(git remote get-url azure)
git push azure staging:main
az webapp deployment slot swap --name monapp-nodejs-2026 --resource-group rg-appservice-tutorial --slot stagingScales to 3 P2v3 instances (more CPU). Creates staging slot, pushes code, and swaps for zero-downtime. Pitfall: slots share the plan; monitor costs with az monitor metrics.
Best Practices
- Use slots for zero-downtime deployments and A/B testing.
- Enable Application Insights:
az webapp insight component createfor automatic traces. - Scaling rules: Auto-scale on CPU >70% via Azure Portal.
- CI/CD with GitHub Actions: Integrate
azure/webapps-deployfor production. - Daily backups:
az webapp config backup create.
Common Errors to Avoid
- Fixed port: Always use
process.env.PORT; otherwise, Azure timeouts. - Memory leaks: Monitor via Kudu (https://monapp.scm.azurewebsites.net); recycle workers.
- Cold starts: Use Premium plan for always-ready instances.
- Lost logs:
console.loggoes to Log Stream; use Winston for persistence.
Next Steps
- Official docs: Azure App Service
- Advanced monitoring: Application Insights
- Expert training: Check out our Learni courses on Azure DevOps and IaC with Terraform.
- ARM example: Deploy via JSON templates for multi-env.