Choosing Where to Deploy
For a simple web app — a Node.js, Python, .NET, or static frontend project without heavy custom infrastructure needs — Azure App Service is almost always the right starting point: it's a fully managed platform-as-a-service that handles the OS, runtime patching, load balancing, and TLS certificates for you, so you deploy just your code. If your app is already containerized, Azure Container Apps is a strong alternative that adds built-in autoscaling (including scale-to-zero) and Dapr integration for microservices patterns without you managing Kubernetes directly. Reaching for a full Azure Kubernetes Service (AKS) cluster or a raw Virtual Machine only makes sense once you have specific needs — a complex multi-container orchestration requirement, or OS-level customization — that a managed PaaS option can't satisfy; starting there for a simple app adds operational overhead with no corresponding benefit.
Cricket analogy: Choosing App Service over a VM is like a franchise renting a fully-equipped stadium with groundstaff already hired, rather than buying raw land and building a ground from scratch — you focus on fielding the team, not maintaining the pitch.
Deploying via the Azure CLI
The fastest path from local code to a running Azure app is the Azure CLI's az webapp up command: run it from your project's root directory and it inspects your code, detects the runtime (Node, Python, .NET, PHP, Java), creates a resource group, an App Service Plan, and a Web App if they don't already exist, and deploys your code as a ZIP package — all in a single command. For more control, you separate the steps explicitly: az group create for the resource group, az appservice plan create to define the compute tier (and OS — Linux is generally cheaper and preferred for most modern stacks), az webapp create to provision the app, and then az webapp deploy or a ZIP-deploy command to push your build artifacts. Once deployed, az webapp log tail streams live logs directly to your terminal, which is often faster for debugging a startup failure than navigating to the portal.
Cricket analogy: az webapp up is like a franchise's one-call operations manager who books the stadium, hires groundstaff, and schedules the match all at once — versus manually calling the venue, caterer, and umpires separately, which is the explicit multi-step CLI flow.
# Quick deploy from your project directory
az login
az webapp up \
--name my-simple-app \
--resource-group rg-simple-app \
--location eastus \
--runtime "NODE:20-lts" \
--sku B1
# Explicit, step-by-step deployment
az group create --name rg-simple-app --location eastus
az appservice plan create --name asp-simple-app --resource-group rg-simple-app --is-linux --sku B1
az webapp create --name my-simple-app --resource-group rg-simple-app --plan asp-simple-app --runtime "NODE:20-lts"
az webapp deploy --resource-group rg-simple-app --name my-simple-app --src-path ./build.zip --type zip
# Tail live logs for debugging
az webapp log tail --name my-simple-app --resource-group rg-simple-appCI/CD with GitHub Actions
Manual CLI deploys are fine for a first push, but any app you plan to iterate on should be deployed through a pipeline. Azure's Deployment Center feature on an App Service can auto-generate a GitHub Actions workflow that builds your code and deploys it on every push to a chosen branch, authenticating via either a downloaded publish profile (simplest, but a long-lived secret) or federated OpenID Connect credentials tied to a Microsoft Entra app registration (the current best practice, since it avoids storing any long-lived secret in GitHub at all). A typical workflow has two jobs: a build job that installs dependencies, runs tests, and produces an artifact, and a deploy job that downloads that artifact and calls the azure/webapps-deploy action — separating build from deploy means a failing test blocks the deployment automatically, before broken code ever reaches production.
Cricket analogy: A CI/CD pipeline is like a domestic first-class system that promotes players to international level: a player (code change) must pass through domestic form (tests) before being selected for the national team (production), automatically filtering out anyone underperforming.
Deployment slots let you deploy to a staging slot (e.g., my-simple-app-staging) with a separate URL, warm it up, and then swap it into production with near-zero downtime — the swap is a VIP swap at the load-balancer level, not a redeploy, so if something's wrong you can swap back instantly. Slots are available on Standard tier and above.
Configuration and Scaling
App Service configuration — connection strings, API keys, feature flags — belongs in Application Settings, which are injected as environment variables at runtime and can be marked 'slot sticky' so they don't swap with a deployment slot (useful for keeping a staging slot pointed at a staging database). For real secrets, the better practice is to store them in Azure Key Vault and reference them from App Service using Key Vault references (@Microsoft.KeyVault(SecretUri=...)), so the secret value never actually lives in the App Service configuration blob, and access is governed by the app's managed identity rather than a shared key. Scaling has two independent dimensions: scale up (a bigger App Service Plan tier, for more CPU/memory per instance) and scale out (more instances behind the built-in load balancer, configured either on a schedule or reactively via autoscale rules watching a metric like CPU percentage or HTTP queue length).
Cricket analogy: Storing secrets in Key Vault instead of app settings is like a team keeping the actual playing XI locked away until toss, revealed only to the match referee, rather than posting it publicly on the dressing room wall for anyone walking past to read.
Never commit connection strings or API keys directly into your repository or bake them into a Docker image, even for a 'simple' app — a public GitHub repo with a leaked key is one of the most common real-world Azure security incidents. Use Application Settings for non-sensitive config and Key Vault references (via managed identity) for anything sensitive.
- Azure App Service is the default choice for simple web apps; reach for Container Apps or AKS only when you have specific containerization/orchestration needs.
az webapp updeploys code in one command; explicitaz group/appservice plan/webapp createsteps give more control.az webapp log tailstreams live logs, often faster for debugging than the portal.- GitHub Actions with OIDC federated credentials is the current best-practice CI/CD pattern, avoiding long-lived secrets.
- Separate build and deploy jobs so failing tests block deployment automatically.
- Deployment slots enable near-zero-downtime releases via a VIP swap, with slot-sticky settings for environment-specific config.
- Use Application Settings for config and Key Vault references (via managed identity) for secrets — never commit secrets to source control.
Practice what you learned
1. Which Azure CLI command deploys a simple app in a single step, auto-detecting the runtime?
2. What is the recommended way to authenticate a GitHub Actions workflow to Azure without storing a long-lived secret?
3. What does an App Service deployment slot swap actually do?
4. Where should a production database connection secret be stored for an App Service app?
5. What is the difference between scaling up and scaling out an App Service?
Was this page helpful?
You May Also Like
Azure Monitor Basics
A practical introduction to Azure Monitor: how it collects metrics and logs, fires alerts, and gives you visibility into application and infrastructure health.
The Azure Well-Architected Framework
An overview of the five pillars of the Azure Well-Architected Framework and how they guide design decisions for reliable, secure, and cost-efficient workloads.
Azure Quick Reference
A condensed cheat sheet of core Azure services, CLI commands, networking basics, and pricing concepts for fast lookup.