skip to Main Content

Deploying Your Web Site to Azure Static Web Apps

💭 Imagine: merging a Pull Request is all it takes to automatically deploy your static or single-page app to a secure, dynamically scaled, and globally distributed network with integrated API support – that’s the promise of Azure Static Web Apps.

Announced during Microsoft Build 2020, Azure Static Web App is a service that automatically builds and deploys static web apps to Azure from a GitHub repository. The features that I find the most interesting are:

  • First-party Github integration
  • Globally distributed
  • Free, auto-renewed SSL certificates
  • Integrated API support by Azure Functions
  • For now – Free hosting for your static site (Angular, React, etc)

I gave it a try and I have to say: it’s pretty cool! 👍 I’ll have the step-by-step on how to configure and deploy an existing site to Azure Static Web Apps below. The steps seem lengthy but there are really just a few basic steps:

  • Create a new “Static Web App” resource and configure basic parameters.
  • Point to the GitHub repository of your app.
  • After a few screens, your app is automatically deployed and available on its own secure URL on Azure Static Web Apps.

If you want to create a brand new site from scratch, see the official documentation

Deploying an Existing Static Site to Azure Static Web Apps

As part of the #100DaysOfCode challenge, I’ve been working on a React site that hosts various programming utilities like encoders/decoders, UUID generator, test data generators, etc. It’s a perfect candidate to test out Azure Static Web Apps.

Create Your Static Web App

First, log into Azure Portal and click “Create a resource“, then search for “Azure static web“. You should see Static Web App (Preview) in the search results. Click on it.

Azure Static Web App - Search

Click Create.

Fill out the Basics tab. Most of the fields are self-explanatory. Click “Sign in with GitHub“.

The page expands, showing a few more fields for GitHub. Fill out with the info for your app’s GitHub repository, and choose “Next: Build>“.

On the Build tab, fill in the appropriate values for “App location“, “Api location“, and “App artifact location“. Then click “Review + create“.

App location” is the root folder for your app. It’s typically / or /app. “Api location” should be left blank if you are unsure. “App artifact location” is the folder to your build.

Review your settings and click Create. Wait a few seconds for the deployment to complete. During the initial deployment, Static Web Apps automatically creates a GitHub Action for you (in the file named azure-static-web-apps-<id>.yml and adds it to your chosen branch. When it’s all done you should see this page:

Click “Go to resource” to go to the resource page for your new Static Web App. On the Overview page, you will see a link to your web app.

Click on “GitHub Action runs” to go over to your GitHub repo and view the status of your deploy Action. You should see a new Action named “ci: add Azure Static Web Apps workflow file”. It should take about two minutes to run.

Switch to the Code tab and see that a new Action file was added to your repo. This is what tells GitHub to automatically build and deploy your app to Azure Static Web Apps.

Bring Up Your Static Web App

It’s time to bring up our web site on Azure Static Web Apps!

Go back to Azure Portal and click on the URL to your app to bring it up. The below screenshot shows my app now running on Azure Static Web Apps with its own unique secure URL.

Custom Domain Name

Adding a custom domain name is pretty straightforward. On Azure Portal, go to the home page of your Static Web App, and click on “Custom domains“, then Add.

On the “Add custom domain” page, note the Azure host name for your site. You will need to create a DNS CNAME record to point your custom domain to that Azure host name. The specifics of this part depends on your domain registrar or web hosting provider. For me, the domain name is hosted on Pair Networks so I went to their control panel and created there CNAME record there.

After you have created your DNS CNAME record, go back to Azure Portal and paste your custom domain into the “Custom domain” box, then click Validate.

Depending on your DNS settings it can take up to 48 hours for a new DNS record to propagate. In practice it should not take more than an hour. In my case it took about 15 minutes. If you get an error in the next step, just wait some time and try again.

After you get the “Validation succeeded” message, click Add to add your custom domain to your Static Web App. This step took about one minute for me

And now I am able to get to the web site via the custom domain name

Adding Server Routes

To handle server routes, you need a routes.json file to your build folder. In my React app, I added it to the /public folder.

Server routing is required to handling “hard” navigation to routes that are handled by your single page app. In my case, I have a React route for /uuid which works fine when you navigate there within the app. But you will get a 404 if you go there directly, or do a browser refresh while you are on that page. Server routes take care of that. See the official docs for more info.

  "routes": [
      "route": "/uuid",
      "serve": "/index.html",
      "status": 200
      "route": "/encode",
      "serve": "/index.html",
      "status": 200
      "route": "/login",
      "serve": "/index.html",
      "status": 200

Troubleshooting Tips

I did run into one problem with a test site. The initial deployment for it did not happen automatically. I verified that the *.yml file was created but the Action never got executed. I was able to get around that by pushing a “dummy” change to the repository.

Game Changer?

Azure Static Web Apps looks to be a game changer. You are getting important features like SSL, dynamic scaling, global distribution, and GitHub deployment all in one easy-to-use package. Once configured, deploying your changes is as simple as pushing code to your GitHub repository. In fact I have deployed several new versions of the app over the past few days and it worked perfectly fine each time.

If cost is reasonable, I would definitely use it on a permanent basis for my single-page/static sites. Currently Azure Static Web Apps is in preview and is free, but things may change after it goes out of preview.

What do you think about Azure Static Web Apps? I would love to hear your thoughts. Let me know here in the Comments section or on Twitter!

Azure Static Web Apps

Finds of the Week – Oct 31, 2007

Here are my finds for this week:



  • I hope my hard drive doesn’t crash in the next few days… because my initial Mozy backup is still running… about 3 weeks after I started it. At this rate it should be done in a few more days.Mozy Backup
  • Oracle SQL Developer is a very nice and full-featured Oracle query and browsing tool. Best of all: it’s free.Oracle SQL Developer

Windows Mobile / Pocket PC

  • I wrote before about how Verizon Wireless may cut you off if you use up too much bandwidth per month. Good news: Verizon Wireless has just settled a N.Y. probe ( into that practice.
  • I’ve been checking my Gmail account everyday every since the IMAP announcement on Oct 24. Today, it finally showed up!Gmail IMAP
  • Capture Screen Utility from Fann Software is a free screen capture program for Pocket PC and Windows Mobile devices. It’s free, and it works.Fann Software Screen Capture Utility for Windows Mobile/Pocket PC


  • If you are anoyed about that pesky Windows Language Bar that keeps coming back after you tell it to go away, you are not alone. Here‘s how to get rid of it for good (How-To Geek Blogs).

It’s OK to Be Lazy

At least when it comes to instantiating objects.

Even in today’s environment, when the typical amount of RAM on each server is in the gigabytes, it’s still wise to pay attention to memory usage. As a developer or architect, you need to be aware of the trade-offs between eager instantiation and lazy instantiation. Yes, it’s rather pointless to consider an Int16 versus an Int32 for a variable if it’s just going to be created and used a few times in the lifetime of your application. However, if that same variable is instantiated thousands of times or more, then the potential improvement in either memory usage or performance (whichever is more important to you) is definitely worth a look.

Eager/Lazy Instantiation Defined

With eager instantiation, the object is created as soon as possible:

Example – Eager Instantiation

public class Customer
    // eager instantiation
    private Address homeAddress = new Address();
    public Address HomeAddress
             return homeAddress;

With lazy instantiation, the object is created as late as possible:

Example – Lazy Instantiation

public class Customer
   private Address homeAddress;
   public Address HomeAddress
           // Create homeAddress if it’s not already created
           if (homeAddress == null)
               homeAddress = new Address();
           return homeAddress;

Eager/lazy instantiation also applies to classes, singletons, etc. The principles and potential advantages/disadvantages are similar. For this article, I am only discussing the instantiation of class members.

CPU Cycles vs. Memory Usage

Eager vs. lazy instantiation is the classic performance/memory trade-off. With eager instantiation, you gain some performance improvement at the cost of system memory. Exactly what kind of performance/memory trade-off are we talking about? The answer depends mostly on the objects themselves:

  • How many instances of the parent object do you need?
  • What is the memory footprint of the member object?
  • How much time does it take to instantiate the member object?
  • How often will the parent object/member object be accessed?

Calculating the Memory Footprint of an Object

According to my own experiments (using DevPartner Studio and .NET Memory Profiler), each reference-type object (class) has a minimum memory footprint of 12 bytes. To calculate the total memory footprint of each reference-type object, add up any other memory used by members in the object. To get the exact memory footprint, you also need to take into consideration “boundaries” but for our purpose that’s probably not important.

The memory foot-print of an object can be closely approximated using the following table (from MSDN Magazine):

TypeManaged Size in Bytes

Using the example Customer class above, let’s say that each Address object take up 1 KByte, and my application frequently needs to instantiate up to 10,000 Customer objects. Just by creating 10,000 Customer objects, we would need about 10 Megabytes of memory. Now let’s say that the HomeAddress member is only needed when the user drills down into the details of a Customer, and we are looking at a potential saving of 10 Megabytes of memory by using lazy instantiation on HomeAddress.

Memory Usage Can Also Impact Performance

Another important consideration with .NET managed code is garbage collection. In .NET managed code, memory usage has a hidden impact on performance in terms of the work the garbage collector has to perform to recover memory. The more memory you allocate and throw away, the more CPU cycles the garbage collector has to go through.


  • Pay closer attention to classes that get instantiated multiple times, such as Orders, OrderItems, etc.
  • For light-weight objects, or if you are not sure, use lazy instantiation.
  • If a member object is only used some of the times, use lazy instantiation.

Additional Reading

Rediscover the Lost Art of Memory Optimization in Your Managed Code

A New Way to Measure Lines of Code

Is Lines of Code a good way to measure programmer output?


First, some background: several studies (Sackman, Erikson, and Grant – 1968; Curtis – 1981) have shown that there are large variations in productivity levels among the best and worst programmers. While the numbers from the studies are controversial, I tend to agree with the basic premise that a super programmer can significantly outperform the average programmer. In my real-world projects, I estimate that variations have ranged up to 5/1.

As a manager or technical lead of a project, it’s important to have a good idea of how productive your programmers are. With a good idea of productivity levels, you can make better estimates for time and resources, and you can manage the individual developers better. Knowing that Programmer A has relatively lower productivity than his teammates, you can assign him smaller features and save the more complex ones for more productive/better programmers. Or, in the case of the negative-productivity programmer, you can identify him quickly and react appropriately instead of letting him continue to negatively impact your project.

So, is Lines of Code (LOC) per Day by itself a good way to measure productivity? I think the answer is a resounding no for many reasons:

  • A good programmer is able to implement the same feature with much less code than the average programmer.
  • Code quality is not taken into account. If you can write a thousand lines of code more than the average programmer, but your code is twice as buggy, that’s not really desirable.
  • Deleting and changing code, activities that are associated with important tasks such as re-factoring and bug-fixing, are not counted, or even counted negatively.

A New Method to Measure LOC

If LOC is not a good way to measure productivity, why am I writing about it? Because it’s still a good metric to have at your disposal, if you use it correctly, carefully, and in conjunction with other data. I also propose a revised method to calculate LOC that can better correlate with productivity. This “new-and-improved” LOC, in conjunction with other data (such as a Tech Lead’s intimate knowledge of his programmers’ style, efficiency, and skill level), may allow us to gain a better picture of programmer productivity.

The traditional way of calculating LOC has always been to count the lines of source code added. There are variations, such as not counting comments or counting statements instead of lines, but the general concept is the same: only lines or statements of code that are added are counted. The problems with the old method are:

  • Buggy code counts as much as correct code.
  • Deleting or changing code is not counted. Deleting/changing code is often done when you are re-factoring, or fixing bugs.
  • Optimizing a 20,000-line module to make it 10,000 lines actually impacts the LOC negatively.

At a conceptual level, my new method to calculate LOC (let’s call it “Lines of Correct Code” or LOCC) only counts correct lines of code, and code that is deleted or changed. Short of reviewing each line of code manually, how does a program know if a line of code is correct? My answer: if it remains in the code base at the end of the produce cycle, then for our purpose, it is “correct” code.

Algorithm for Counting Lines of Correct Code

Below is the proposed algorithm for calculating the LOCC. It should be possible to automate every of the steps described here using a modern source control system.

  • Analyze the source code at the end of the product cycle and keep a picture of the code that exists at the end. This is our base-line “correct” code.
  • Go back to the beginning of the project cycle and examine each check-in. For each check-in, count the lines of code that is added or changed and remains until the end. Lines of code that are deleted are also counted.
  • Auto-generated code is not counted or is weighted appropriately (after all, some work is involved).
  • Duplicate files are only counted once. In many applications, some files are mirrored (shared in SourceSafe-speak) in multiple locations. It’s only fair to count these files only once.

Ways to Use Lines of Correct Code

Here are a few ways I am planning to use LOCC in my projects:

  • Look at the LOCC per day (week/month) of the same developer over time.
  • Compare the LOCC per day between different programmers of equal efficiency and skill level.
  • Compare the total LOCC between different projects to get an idea of their relative size.
  • Correlate the LOCC of a programmer against his/her bug rate.
  • If a programmer writes code that is often deleted or changed later on, try to find out why.

Tell me what you think. Is this LOCC metric something that you would consider using in your project? I am writing a utility to calculate LOCC automatically from SourceSafe and if there’s sufficient interest, I will consider making it available.

StringBuilder is not always faster – Part 1 of 2

How often have you been told to use StringBuilder to concatenate strings in .NET? My guess is often enough. Here is something you may not know about string concatenation: StringBuilder is not always faster. There are already many articles out there that explain the why’s, I am not going to do that here. But I do have some test data for you.

When concatenating three values or less, traditional concatenation is faster (by a very small margin)

This block of code took 1484 milliseconds to run on my PC:

for (int i = 0; i <= 1000000; i++) 
    // Concat strings 3 times using StringBuilder 
    StringBuilder s = new StringBuilder(); 

And this one, using traditional concatenation, took slightly less time (1344 milliseconds):

for (int i = 0; i <= 1000000; i++) 
    // Concat strings 3 times using traditional concatenation 
    string s = i.ToString(); 
    s = s + i.ToString(); 
    s = s + i.ToString(); 

The above data suggests that StringBuilder only starts to work faster once the number of concatenations exceed 3.

Building strings from literals

When building a large string from several string literals (such as building a SQL block, or a client side javascript block), use neither traditional concatenation nor StringBuilder. Instead, choose one of the methods below:

+ operator

// Build script block 
string s = "<script>" 
       + "function test() {" 
       + "  alert('this is a test');" 
       + "  return 0;" 
       + "}";

The compiler concatenates that at compile time. At run-time, that works as fast as a big string literal.

@ string literal

I sometimes use the @ string literal which allows for newlines (I find this syntax is harder to maintain, formatting-wise, than using the + operator):

string s = @"<script> 
        function test() { 
        alert('this is a test'); 
        return 0; 

Both methods above run about 40 times faster than using StringBuilder or traditional string concatenation.

Rules of Thumb

  • When concatenating three dynamic string values or less, use traditional string concatenation.
  • When concatenating more than three dynamic string values, use StringBuilder.
  • When building a big string from several string literals, use either the @ string literal or the inline + operator.

Updated 2007-09-29

I have posted a follow-up article to provide more detailed analysis and to answer some of the questions asked by readers.

Back To Top