Static web hosts have come a long way since dropping your bundle into an S3 bucket. Netlify and Azure Static Web Apps (SWA) both offer a free tier and the two are surprisingly similar in terms of features. In this post I’ll compare the two and look at the small differences that make me ultimately prefer Netlify.

Creating the SPA

Let’s create a simple static website and build an artifact for deployment. We’ll use the resulting dist directory to deploy to both Netlify and Azure Static Web Apps.

npm create vite@latest -- --template react-ts my-react-app
cd my-react-app
npm i
npm run build

Deploying to Netlify

Create a free account on Netlify, install the Netlify CLI and login. Once logged in, create a new site and deploy the dist directory:

npm install netlify-cli -g
netlify login
netlify sites:create
netlify deploy --prod --dir dist

Just like that, the site is up and publically accessible:

Deploying to Azure Static Web Apps

Azure Static Web Apps has a Visual Studio Code extension that can be used to create and manage static web apps, however, for comparison’s sake I’ll use the SWA CLI. In theory, and I guess outside of WSL2, it should be simple:

npm install -g @azure/static-web-apps-cli
swa

However even swa login fails for me, and I was hit with these bugs and errors:

The workaround for this is to (install and) use the Azure CLI to login and then use the SWA CLI. Note that this requires a valid subscription which will not be present on a new Azure account. Adding a Free Trial subscription on Azure requires both a Mobile phone number and a Credit Card. Once a subscription is added, the following can be done:

npm install -g @azure/static-web-apps-cli
az login --tenant MY_TENANT_ID
swa login

Deployment at this stage will result in:

The subscription is not registered to use namespace ‘Microsoft.Web’

So register the Azure Static Web Apps resource provider and then deployment should succeed:

az provider register --namespace Microsoft.Web
swa deploy --env production

A few more steps, and some head banging with Azure account caching in the browser, but ultimately the site is up and publically accessible:

APIs and CORS

Say now we have some API on another host, that does not have CORS enabled, and we don’t have control over that host to add those headers. For example, this deployment of the Dog API. In both the local, and deployed environments, calling this API will result in the following CORS error:

Access to fetch at ‘http://dog-api.kinduff.com/api/facts’ from origin ‘http://localhost:8888’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

Thankfully, Netlify has us covered and adding the following to netlify.toml and fetching /dogs will solve this error for us both during local development, and, in the deployed environment:

[[redirects]]
  force = true
  from = "/dogs"
  status = 200
  to = "http://dog-api.kinduff.com/api/facts"

Azure Static Web Apps has something similar, but it only works in the deployed environment. Adding the following to staticwebapp.config.json solves for the deployed environment but swa start does not honour this configuration:

{
  "routes": [
    {
      "route": "/dogs",
      "redirect": "https://dog-api.kinduff.com/api/facts"
    }
  ]
}

Netlify’s rewrite and redirect functionality is quite flexible where Azure Static Web Apps routes configuration is more limited, misses functionality like passing on query strings, and is a little buggy.

Serverless Functions

Both services offer serverless functions on their free tiers and adding them is quite simple. For Netlify, netlify functions:create will ask some questions and add your first function. Functions are available via /.netlify/functions/your-function and are available both locally with netlify dev and in the deployed environment with netlify deploy.

Azure’s SWA CLI can run functions locally but adding them to the project requires either installation of Azure Functions Core Tools or (the easier approach) is to install both(!) the Azure Functions and Static Web Apps extensions for vscode. After adding a function with vscode running the app with swa start dist --api-location api serves the function on /api/your-function. Deploying the function along with the site is similar with:

swa deploy --api-location api --env production

Preview Environments

Finally, both services offer preview environments: non-prod environments either deployed directly via CLI or (for example) from a GitHub PR. Netlify takes preview deployments even further with their Drawer Feature, though I haven’t personally used it. To deploy a preview environment with Netlify, just omit the --prod flag. For Azure, the relevant Github Actions are configured when using the vscode extension to create the static web app, or, by using the --env flag with the swa deploy command.

Conclusion

Over all the offerings are quite similar and almost have feature parity. Netlify’s CLI is more mature and easier to use, and the platform has a few more features that make it more appealing to me. Azure Static Web Apps has a few more steps to get started, but the platform is more integrated with the Azure ecosystem and may be more appealing to those already using Azure services. Both services are free for small projects and are a great way to get started with static web hosting.

All of the commands I ran in this post were done against the same project which can be deployed to both Netlify and Azure Static Web Apps (and were - the iframes above point to the live sites). The source code for this can be found here.