.Net and Azure

Azure web app deployment modes


Azure Web Apps is probably the most commonly used PaaS product in azure.

With direct support for .Net, Java, NodeJS and PHP they offer a great term of flexibility in terms of runtime environments.

The same can be said about the various modes of deployment and this post aims to give a brief overview and description of each.

RunFromPackage (Mode=Url)

This is the newest deployment mode available. Instead of deploying individual files to the webserver you upload a zip file to blob storage, then you set the environment variable RUN_FROM_PACKAGE to the SAS token of the zip file (or really any public url, so you can even host your web app zip in S3 buckets if you wish).

The webapp will then download the zip file and directly mount it as the site\wwwroot folder on startup.

This has a few interesting behaviours:

How it works:


For applications with many files to load on startup (such as nodejs with its giant node_modules folder and js files) this actually improves performance, because disk I/O now reads from a single continuous filestream (the zip file) instead of many tiny files as would usually be the case.

The Azure team has created a virtualized driver that enables this behaviour on the fly. Your webapp won’t know the difference between reading from disk or from the (locally cached) zip file.


The last point is the biggest disadvantage: Your webapp now depends on this URL not expiring and the zip file existing in storage account as any restart will trigger a redownload.

Along with the public SAS token URL I do not personally like this deployment model and actually prefer the next one:

RunFromPackage (Mode=1)

This deployment mode is similar to the one above except:

It is much more secure and still has all the benefits. I actually use this mode for all my personal websites.

To use it, you can use Azure DevOps task App Deploy (v4) and choose Mode=RunFromPackage, it will default to uploading the zip to the webapp.

To manually get it running you would have to:

Once the content of the .txt file changes, the webapp restart is automatically triggered, but again Azure DevOps will hide all those details from you if you use the App Deploy task, making this deployment method very convenient.

The endresult is the same as mentioned above:

Read more about it here.


The oldest and most well known deployment model. While this is still supported I won’t cover it in details as I don’t think it should be used anymore (I personally disabled it on all web apps as I consider it a security risk).

If you are manually uploading files via FTP(S) in 2019 then you are doing DevOps wrong!

Publish from Visual Studio

This is technically a deployment mode (although it uses webdeploy under the hood) but I still want to mention it seperately.

It certainly is great if you are deploying a hobby website from your local machine or are doing a 5 minute webcast, but I personally avoid it for multiple reasons:

Firstly: I don’t consider it a good practice for deployment.

For testing you can just start the webapp locally and when a deployment is needed I recommend you use a regular pipeline: git commit -> build with tests -> release that deploys your web app in a consistent manner.

This makes everything reproducable and I’ve had my fair share of “minor changes” that I just wanted to publish that happened to be faulty because manual steps are always prone to error.

If you are not using an automated deployment pipeline in 2019 I would serious suggest you reconsider your deployment methods because the tooling has gotten really good and all the parts are free (Azure DevOps offers 1800 free build minutes per month for private projects and unlimited build minutes for open source projects).


This will upload all files individually and you can choose to use App_offline.htm in the meantime.

You can also optionally choose to delete all other files to achieve consistent deployments.

Generally this mode will often have problems with files being locked (hence the MS_PUBLISH_RENAME_LOCKED_FILES workaround that works some of the time).

Choose this method if you need to have a writeable wwwroot directory.


Same as WebDeploy but uploads & extracts a zip. This improves the upload speed (if you have many tiny files to be uploaded) but may still run into the “file locked” issue mentioned above as it will just extract the zip file content to wwwroot folder.


If you want to use containers but don’t want to manage Kubernetes (or don’t have the need for full orchestration) this can allow you to use the PaaS infrastructure of App Services with your own containers.

If you already plan to migrate to containers it may be a decent first step as you get the scaling abilities of the app service plan with the consistent developer experience of containers.

Staging slots

This isn’t technically a deployment mode in the same sense as all the other ones but I still wanted to mention it because I think it should be used with every deployment.

The problem:

If you deploy directly to your webapp you kill the existing process and the new process will take a bit to start up - or worse: fail to start.

In this case you are left with a nonfunctional website and even on a successful deploy there will be a window of up to 30 seconds where the web app won’t respond to incoming requests due to startup taking some time.

The solution:

Slots work around this issue by allowing you to deploy your app to a secondary web app (the slot) which has a seperate url: yourwebapp-<slot name>.azurewebsites.net. You can pick your own slot name and you can even create up to 5 (Standard tier) or 20 (Premium tier) slots per web app, although the most common use case is just one slot: staging

The slot behaves like a regular web app and can run through warmup to ensure it is operational.

Afterwards swapping the slot with the production instance is a zero-downtime operation as a DNS swap will happen in the background. All existing requests to the old instance will be honored and processed until the new instance is fully swapped into place.

Many companies will run health checks or light workloads against these slots to ensure they are working correctly (in combination with multiple environments of course) before swapping the slots into production.

If you want to, you can even delegate a certain percentage of your users to the slot as scaling between 0-100% traffic can be done freely between the production app and all slots.


Lots of different options with various tradeoffs.

From personal experience staging slots in combination with RunFromPackage (Mode=1) offers the most convenient solution and it’s also what I use in all my private projects as the (small) overhead in complexity is well worth the benefits it provides.