Github Actions for Flutter with Caching

Matt Solle
2 min readMar 10, 2021

Github Actions provides an incredible tool for automation. Automation which costs us some up front developer time to setup and then provides a continual decrease in cost for the long run. Unfortunately for iOS, Github Actions come with a hefty penalty for using MacOS: a ten-times multiplier for MacOS instance minutes. The 2,000 minute limit for free accounts suddenly becomes a lot more daunting when we realize that is only 200 minutes for our iOS workflow to execute each month. If the average workflow takes two minutes, that is only 100 runs for month. Thankfully we can alleviate this issue do a degree by using caching.

This template can be used to create a cached Flutter environment for testing, building, analyzing, etc. With its current implementation, when an individual pushes to develop or master, this workflow will run the Dart analyzer and all tests in the project. Using caching, it will preserve the Flutter runtime to minimize setup time for each successive execution of the workflow (and reduce the risk of going over Github Action limits to avoid increased costs).

Template analyzes code and runs all tests

The Flexible Pieces

on:                         
push:
branches: [develop, master]

The block indicates the prerequisite git action that will result in our workflow executing. In this example we execute any jobs on all pushes to the develop or master branches. Another notable option here would be pull_request:. This will allow us to differ strictness or separate out compiling APKs from more normal workflows such as if we wanted to run tests on every push but only run the Dart analyzer on pull requests.

env:                         
flutter_version: '1.20.x'

We pull out the Flutter version for two reason:

  1. Make changing Flutter version easy and centralized
  2. Embed the version into the cached file name so different versions of Flutter will have their own cache.
runs-on: ${{ matrix.os }}                           
strategy:
matrix:
os: [ubuntu-latest]
include:
- os: ubuntu-latest
flutter_path: /opt/hostedtoolcache/flutter

While this template only uses Ubuntu, it is written to be mold-able into as many operating systems as needed. Using a matrix allows us to provide a list of options operating systems which will individually run the Dart analyzer and our tests. It could be updated to include multiple operating systems as follows:

runs-on: ${{ matrix.os }}                           
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
include:
- os: ubuntu-latest
flutter_path: /opt/hostedtoolcache/flutter
- os: windows-latest
flutter_path: [path-for-windows]
- os: macos-latest
flutter_path: [path-for-macos]

Lastly, the caching itself:

- uses: actions/cache@v1                               
with:
path: ${{ matrix.flutter_path }}
key: ${{ runner.os }}-flutter-install-cache-${{ env.flutter_version }}

Here, we utilize the Cache action. The path is used for storing the actual path itself and will be different absolutely values depending on the operating system (e.g. C:\path\to\cache versus /home/user/path/to/cache). The key is the unique identifier for storing or retrieving the cache itself. If we left the flutter_version variable off the end, we could end up testing with a different cached version than what we are specifying for flutter-action.

--

--

Matt Solle

Fulltime Flutter developer with deep expertise in React Native, C#, SQL, and a million small things along the way.