Azure Static Web Apps with Sapper + Azure Functions

In the last post, I walked through setting up a simple Sapper application on Microsoft’s new Azure Static Web Apps. In this post, I’ll walk through my experience adding and deploying an Azure Functions API.

TL;DR Azure Static Web Apps currently only supports Azure Functions v3 with Node.js v12 and HttpTrigger bindings for APIs. See the docs.

First things first, you’ll need the Azure Functions Core Tools. You can install the latest version 3 with npm:

npm install -g azure-functions-core-tools@3 --unsafe-perm true

From the root directory of your static app project, you’ll want to create a new directory and initialize it for Azure Functions:

mkdir api && cd api
func init ...

When I then tried to create my function, however, I received a nice little error message like the one reported here. The issue is reportedly fixed, though I was still finding it happening a few days ago. This comment provides a workaround. I’ll assume those of you following along either have a newer, working version or applied the suggested fix and proceed.


I’ve been learning Python recently, so I thought it would be fun to have a Python API to run alongside my static app and thereby continue learning two things at once. If you, unlike me, have already read through the ever-expanding documentation, you’ll have stumbled upon the docs for APIs and realized where this post is heading.

I added a function using with the following command:

func init --worker-runtime python
func new -l python -t HttpTrigger -n hello
cd ..
git checkout -b python # create a new branch off master
git add .
git commit -m "Add Python api"

Easy peasy.

I then went to GitHub, opened a PR from my python branch against master, and opened GitHub Actions to watch the magic happen.

Successful build with python?

The build succeeded, and aside from the weird bit about Enumerating repo to find any files with extension 'csproj'..., everything seemed to go off without any problem.

When I navigated to the Azure Portal, however, there were no functions listed. Looking back at the above you’ll notice a few additional lines that I missed on my first glance:

Error: could not detect the language from repo.
Oryx was unable to determine the build steps. Continuing assuming the assets in this folder are already build. ...

Something called Oryx is apparently responsible for the builds and apparently didn’t like that I used Python. I’ll cover more on Oryx in a later blog post.


While waiting on the above to run, I also started another branch using node, as I wanted to get a sense for how this all worked. Lucky for me, b/c if you have by now read the doc linked above, you’ll have learned that only Node will work and only on Azure Functions v3 with only HttpTriggers. I lucked out on two of the three. Actually this is worth calling out, so I’ll quote the docs:

Azure Static Web Apps provides serverless API endpoints via Azure Functions. By leveraging Azure Functions, APIs dynamically scale based on demand, and include the following features:

Integrated security with direct access to user authentication and role-based authorization data.
Seamless routing that makes the api route available to the web app securely without requiring custom CORS rules.
Azure Functions v3 compatible with Node.js 12.
HTTP triggers and output bindings.

Here’s how I created a simple Node Azure Function:

func init --worker-runtime node --language typescript
func new -l typescript -t HttpTrigger -n hello
cd ..
git checkout -b node # create a new branch off master
git add .
git commit -m "Add TypeScript api"

I was inspecting the Python build and trying to figure out what happened while the following build ran. Having assumed this completed, I was surprised to learn that the build failed.

Failed build with node?

I’ve highlighted the issue. The build didn’t fail, only the deployment. However, that was sufficient to cause the build to be marked as a failed build. It turns out, at least during the preview, you can have only 1 pre-production environment per app. Again, read the documentation. They’ve done a great job making sure to address these types of things if you will, unlike me, just read them.

I removed the python environment from the Azure Portal and triggered a rebuild in GitHub Actions.

Successful build and deployment with node!
Just like Lego Batman: “First try!”
Azure Static Web Apps comment on PR!

Azure Static Web Apps sends a link to the pre-production environment in a comment to your pull request (PR)! This makes it really easy to then navigate to your site and start testing things out. (Note the -2 at the end of the sub-domain, which is the number for the pre-production environment.)

Working API!
API working with query string parameter

Azure Portal

Back in the Azure Portal, you can see the functions and environments deployed for your Azure Static Web App.

To see the available functions, select Functions from the side navigation.

This defaults to the production environment. It will also reset to the Production environment anytime you click the Refresh button.

If you choose a different environment, you’ll see the functions available for that environment.

If you select Environments from the side navigation, you’ll see your production and any pre-production, or Staging, environments you’ve deployed.

The fact that the UI supports multiple gives me hope that the platform will eventually support more than one pre-production environment, meaning that this will be a great platform for supporting feature branch previews, something I’ve been doing with a bunch of scripts in the past.

Promoting to Production

When you merge your PR to master, you will notice that two GitHub Actions are triggered, one against master, and one against your PR branch.

The master branch build will deploy to your production environment. What’s even more helpful and convenient is that the other build cleans up the pre-production environment!

I love this! Cleaning up unused environments was always a tedious process for my multi-branch support I set up in the past. I really appreciate that Azure Static Web Apps provides this infrastructure.

In the Portal, you’ll notice our Production environment now has the function deployed.

We can also hit the API against the production endpoint.

And of course, our Sapper app continues to cheer us on!

Wrapping Up

While you can certainly find a much terser walkthrough in the Azure Static Web Apps documentation, I thought this meandering walkthrough worthwhile for showing what may also be possible and what we may expect to see in upcoming releases. I have several planned follow-up posts to show some current work-arounds, as well as some interesting use cases, so stay tuned.

You may also be interested to see what the rest of the community is creating. You can find a collection of samples on GitHub.