Aakash Bhardwaj SharePoint, Office 365 and Azure

Teams App Deployment to Azure Web App


Recently I was working on a Teams app development using yo teams generator for one of my clients. The documentation for getting started and creating a Teams tab from scratch was really helpful and allowed for a smooth development experience.

But when it was time to deploy the application to an Azure Web App to check if everything was working as expected, outside of the local developer environment, I found the documentation a little bit lacking as most of the articles I found only mentioned ngrok for serving the app locally. With no prior experience on working with an Express based Node.Js application I found the deployment process a bit tricky. So once I was able to set it up successfully, I decided to put together the different pieces I learned related to the deployment process. This article describes how to deploy a Teams app to Windows Azure Web App using the Local Git Deployment option.


  • A Node.Js based Teams app needs to be created using the yo teams generator.
  • An Azure subscription is required to create the Azure Web App.

Azure Web App

Create a new Azure Web App with the below options using the Azure portal:

Azure Web App Options

  • Code as the Publish option.
  • Windows as the Operating System.
  • Node as the Runtime Stack.

Kudu Deployment Script

Using Git deploy to publish an app to Azure Web App enables automatic deployment once the changes are pushed. But sometimes we want to customize the deployment process to add some more steps to the deployment process. There is a custom deployment script generator for Kudu called Kudu Script that generates a deployment script which can be updated as per the requirement.

For our app deployment we will use a custom deployment script using the below steps:

  • Install kuduscript tool globally using the below command.
    npm install kuduscript -g
  • Run the below command in the root of the Teams app repository to create the deployment script for a Node.js application.
    kuduscript -y --node
  • This will generate two files
    • .deployment - Contains the command to run for deploying your site.
    • deploy.cmd - Contains the deployment script (or deploy.sh if running on Mac/Linux).
  • Update the deploy.cmd file with the below content that contains steps specific for a yo teams generated project.
@if "%SCM_TRACE_LEVEL%" NEQ "4" @echo off

:: ----------------------
:: KUDU Deployment Script
:: Version: 1.0.9
:: ----------------------

:: Prerequisites
:: -------------

:: Verify node.js installed
where node 2>nul >nul
  echo Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment.
  goto error

:: Setup
:: -----

setlocal enabledelayedexpansion

SET ARTIFACTS=%~dp0%..\artifacts





  :: Install kudu sync
  echo Installing Kudu Sync
  call npm install kudusync -g --silent
  IF !ERRORLEVEL! NEQ 0 goto error

  :: Locally just running "kuduSync" would also work
  SET KUDU_SYNC_CMD=%appdata%\npm\kuduSync.cmd
goto Deployment

:: Utility Functions
:: -----------------


  :: The following are done only on Windows Azure Websites environment
  IF !ERRORLEVEL! NEQ 0 goto error

  IF EXIST "%DEPLOYMENT_TEMP%\__nodeVersion.tmp" (
    SET /p NODE_EXE=<"%DEPLOYMENT_TEMP%\__nodeVersion.tmp"
    IF !ERRORLEVEL! NEQ 0 goto error
  IF EXIST "%DEPLOYMENT_TEMP%\__npmVersion.tmp" (
    SET /p NPM_JS_PATH=<"%DEPLOYMENT_TEMP%\__npmVersion.tmp"
    IF !ERRORLEVEL! NEQ 0 goto error

    SET NODE_EXE=node

) ELSE (

goto :EOF

:: Deployment
:: ----------

echo Handling node.js deployment.

:: 1. Select node version for build
call :SelectNodeVersion
:: 2. Install npm packages
  call :ExecuteCmd !NPM_CMD! install
  IF !ERRORLEVEL! NEQ 0 goto error
:: 3. Build it
  call :ExecuteCmd !NPM_CMD! run-script build
  IF !ERRORLEVEL! NEQ 0 goto error
:: 4. KuduSync
  call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_SOURCE%" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
  IF !ERRORLEVEL! NEQ 0 goto error
:: 5. Select node version for run
call :SelectNodeVersion

goto end

:: Execute command routine that will echo out when error
set _CMD_=%*
call %_CMD_%
if "%ERRORLEVEL%" NEQ "0" echo Failed exitCode=%ERRORLEVEL%, command=%_CMD_%
exit /b %ERRORLEVEL%

echo An error has occurred during web site deployment.
call :exitSetErrorLevel
call :exitFromFunction 2>nul

exit /b 1


echo Finished successfully.

Local Git Deployment

There are various deployment options present in Azure such as Azure DevOps Repos, GitHub, bitbucket, and Local git repository. If we just want to deploy the app for testing and don’t want to create any pipelines yet, we can use the Local Git Deployment option.

The below steps can be followed for enabling local git deployment on our Azure Web App:

  • Go to the Deployment Center settings tab for the Azure Web App and save Local Git as the deployment option. This would generate a Local Git Uri. Copy this as this would be needed later. Local Git Deployment Settings
  • Go to the project’s root directory and initialize an empty Git repository using the below command.
    git init
  • Add an azure Git remote pointing to the Local Git repository URL copied in one of the previous steps using the below command.
    git remote add azure LOCAL_GIT_REPO_URL
  • Add and commit the changes.
    git add .
    git commit -m "Initial commit"
  • Push the changes to the web app using the below command.
    git push azure master
  • The first time changes are pushed some credentials would be required. To get the credentials go to the Local Git tab of the web app’s Deployment Center settings and use the Application Scope Username and Password. Git Deployment Credentials
  • Once the deployment is completed, go to the app URL and check if our Teams app is working or not. Deployed App

There is also an Azure App Service extension for VS Code, currently in preview, that can be used to carry local git deployment of our app. Using it the credentials don’t have to be entered manually while pushing the code changes if we are signed in to our Azure subscription in VS Code. Deployment steps using the extension are mentioned at this link.


If we see that the app is not working as expected, we can go to the Advanced Tools section of the Web App and make the below checks in the Kudu explorer.

  • Check that all the build generated files are present at the path site/wwwroot/dist.

  • Check that a web.config file is present at site/wwwroot. This file that tells the IIS server to use issnode module for hosting the application and also specifies dist/server.js as the entry point to the application. It is automatically generated during git deployment process and has a content similar to the below file.

<?xml version="1.0" encoding="utf-8"?>
     This configuration file is required if iisnode is used to run node processes behind
     IIS or IIS Express.  For more information, visit:


    <!-- Visit http://blogs.msdn.com/b/windowsazure/archive/2013/11/14/introduction-to-websockets-on-windows-azure-web-sites.aspx for more information on WebSocket support -->
    <webSocket enabled="false" />
      <!-- Indicates that the server.js file is a node.js site to be handled by the iisnode module -->
      <add name="iisnode" path="dist/server.js" verb="*" modules="iisnode"/>
        <!-- Do not interfere with requests for node-inspector debugging -->
        <rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
          <match url="^dist/server.js\/debug[\/]?" />

        <!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
        <rule name="StaticContent">
          <action type="Rewrite" url="public{REQUEST_URI}"/>

        <!-- All other URLs are mapped to the node.js site entry point -->
        <rule name="DynamicContent">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
          <action type="Rewrite" url="dist/server.js"/>
    <!-- 'bin' directory has no special meaning in node.js and apps can be placed in it -->
          <remove segment="bin"/>

    <!-- Make sure error responses are left untouched -->
    <httpErrors existingResponse="PassThrough" />

      You can control how Node is hosted within IIS using the following options:
        * watchedFiles: semi-colon separated list of files that will be watched for changes to restart the server
        * node_env: will be propagated to node as NODE_ENV environment variable
        * debuggingEnabled - controls whether the built-in debugger is enabled

      See https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config for a full list of options
    <!--<iisnode watchedFiles="web.config;*.js"/>-->


In this way a Node.Js based Teams app can be deployed to an Azure Web App using Local Git Deployment. For production scenarios Azure pipelines or GitHub Actions can be set up for automatic deployment and this article by Wictor Wilen can be used for such cases.