Search results provided by Azure Search - read how I built it in this post.
Max Melcher

4 minute read

Migration to Azure Static Web Apps

My blog has a bit of legacy: From Wordpress to Hugo. From Azure App Service to Azure Static Websites on Azure Blob. And in this post, I tell you about my migration to Azure Static Web Apps.

Azure Static Web Apps

Azure Static Web Apps are generally available since May 2021 - and I waited way to long to migrate this blog to it, they are amazing! CDN, CI/CD, Custom Domain with SSL - pretty much everything that I puzzled together in previous iterations - “AS A SERVICE” for free (or little money).

Old Setup

The old setup used Azure DevOps for the hosting of my markdown files. Once I committed new files the following tasks were executed in an Azure DevOps pipeline:

  1. Latest version of hugo was installed
  2. Hugo compiled the website and pushed it to Azure Storage.
  3. Azure CDN was purged
  4. Azure Cognitive search indexer ran

The old hosting environment was working well, actually no real need to change. Except, I wanted to learn more about move from Azure DevOps to GitHub, GitHub actions, and simplify the Azure CDN, Azure Storage and bit of history here and there.

Moving to GitHub

Firstly, I thought moving to GitHub will be easy. Create the git repository, adding a git remote, push and done. Then I learned that I have files bigger than 300MB in my repo and I had to remove it.

For this, the recommended way is to use git-filter-repo. Setting this up on Windows simply did not work - Debian in WSL2 to the rescue, it took minutes. Later on I nuked the entire repository, well, I learned a bit here and there.

GitHub Action & Azure Static Web App

Then I create the Azure Static Web App and connected it to the GitHub repository. The GitHub Action workflow ran right afterwards, it detected my Hugo blog, compiled and published it. Colour me impressed!

But, for my custom-built blog search, I need to provide a JSON file to Azure Cognitive Search, in my case I upload it to Azure Blob Storage.

The final tasks are now:

  1. actions/checkout@v2 (get the code)
  2. peaceiris/actions-hugo@v2 (compile hugo)
  3. Azure/static-web-apps-deploy@v1 (deploy to Azure Static Web Apps)
  4. bacongobbler/azure-blob-storage-upload@v1.2.0 (upload the feed.json to Azure Storage)
  5. satak/webrequest-action@master (start the Azure Cognitive Search indexer on that json file)

And the workflow is:

name: Azure Static Web Apps CI/CD
      - main
    types: [opened, synchronize, reopened, closed]
      - main
    if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
    runs-on: ubuntu-latest
    name: Build and Deploy Job
      - uses: actions/checkout@v2
          submodules: true
      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
          hugo-version: 'latest'
      - name: Build
        run: hugo --enableGitInfo --i18n-warnings --verbose --cleanDestinationDir --destination public
      - name: Build And Deploy
        id: builddeploy
        uses: Azure/static-web-apps-deploy@v1
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_RED_SAND_087339603 }}
          repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
          action: "upload"
          ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
          # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
          app_location: "/public" # App source code path
          api_location: "" # Api source code path - optional
          output_location: "public" # Built app content directory - optional
          skip_app_build: true
          ###### End of Repository/Build Configurations ######
      - uses: bacongobbler/azure-blob-storage-upload@v1.2.0
          source_dir: public/feed
          container_name: feed
          connection_string: ${{ secrets.storage }}
          extra_args: '--pattern *.json'
          sync: false
      - name: Start Azure Search Indexer
        uses: satak/webrequest-action@master
          url: https://melcher.search.windows.net/indexers/azureblob-indexer/run?api-version=2017-11-11
          method: POST
          headers: '{"api-key": "${{ secrets.azuresearchkey }}"}'
    if: github.event_name == 'pull_request' && github.event.action == 'closed'
    runs-on: ubuntu-latest
    name: Close Pull Request Job
      - name: Close Pull Request
        id: closepullrequest
        uses: Azure/static-web-apps-deploy@v1
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_RED_SAND_087339603 }}
          action: "close"

The entire run takes roughly 3 minutes for my blog with roughly 250mb of stuff in it.


In Azure DevOps, maybe because of a 350MB file that I checked in, I used git lfs. Somehow I managed to add all my PNG pictures to that storage. In the GitHub Action [actions/checkout@v2] you have to explicitly to checkout LFS files. I tried to figure out why the PNG were not shown, but the JPG files were. I then reached out to Anthony Chu on Twitter - and he figured this out in seconds, you need to add a lfs: true in the checkout action. Very much appreciated!

- uses: actions/checkout@v2
    submodules: true
    lfs: true


I learned a ton of things and as crazy as it might sound - I had fun migrating it. Getting rid of old components and simplifying things is a nice benefit, too.

Kudos to the Azure Static Web Apps service team - you won me as fan.
Send stickers, please.

comments powered by Disqus