Continuous Delivery for Mobile Apps How we deliver Authentiq ID using Gitflow, NeverCode, Fabric and TestFlight.

At Authentiq we have been optimising the process by which we develop, build, test, and publish our mobile apps for iOS and Android. In this post we share our current workflow, a marriage of Gitflow, NeverCode, Fabric and TestFlight.

NeverCode iOS builds


Like many mobile app developers, we started out with our source code in a hosted Git repository like GitHub or GitLab, building the apps in the respective IDEXCode and Android Studio—and then manually distributing test versions to both internal and external testers. When we had a good version we published it on the spot. Presto!

Obviously there are several issues with this approach, which we identified as follows.

Parallel feature work

The simplistic flow did work reasonably well for a linear, master-only, development model, where commits are always in order. However, such a model has disadvantages, and our process broke down entirely as soon as we had multiple developers and several features being worked on and tested in parallel.

Continuous Integration

One benefit of Continuous Integration is that it relieves the developer from the mental burden of making sure that all tests pass before publishing a release. But not being told instantly what change “broke the build” becomes a critical problem once the team grows, or even when features are just developed asynchronously. Test automation is an essential ingredient for a mobile development workflow.

Continuous Delivery

If rolling out updates to testers is laborious, then the feedback cycle isn’t optimal either. If publishing releases to the app stores is hard work, then releases are just going to fall through the cracks since chances are the process is just abandoned while waiting for one of the steps. Our simplistic process didn’t automate either of these at first, and later only test releases via Crashlytics.

Test group management

We didn’t have an easy way to manage groups of testers. Collecting device identifiers of the testers, and adding them to the Apple Developer Dashboard and the ad hoc provisioning profile was clumsy. Moreover, distributing .ipa and .apk files to testers, especially for iOS, wasn’t ideal (although this became much easier when Apple acquired TestFlight).

Our requirements

After identifying these problems, we set out to find a more elegant, more scalable workflow, backed by tools and practices accepted by the industry. We wanted our new workflow to do at least the following:

  • Build upon, and integrate with Git;
  • Run tests after every commit;
  • Make new builds available to testers automatically;
  • Support parallel feature development;
  • Automate publishing to the app stores;
  • Have a process to roll out hotfixes;
  • Post build notifications to Slack.

Having worked with Gitflow before, we began to utilise that as an interface to the deployment process. If you are new to Gitflow, here is a useful Git helper extension you can install to get started.

Developer workflow

Our workflow is entirely driven off of Git, and we find that Gitflow maps wonderfully on to our desired release process. The following mapping of Git branches to releases is used:

Branch Purpose Audience
feature/foo-bar Continuous feature testing Internal testers
bugfix/foo-baz Continuous bugfix testing Internal testers
develop Continuous integration testing Internal testers
release/x.y.0 Release candidates External testers
hotfix/x.y.z Hotfix release candidates External testers
master Latest public release Generally available

Next, we used NeverCode as the glue between Git, Crashlytics, TestFlight, and the app stores. It picks up changes from the various branches, runs unit and UI tests, and sends build artefacts to either Crashlytics or one of the app stores, as shown in the following diagram.

Mobile apps Continuous Delivery workflow

Feature development

As a developer you start new work by creating a feature or bugfix branch.

git flow feature start make-a-space-rocket

Publishing feature branches to the central repository will continuously trigger a build pipeline on NeverCode. This will build and test the app, and make a new release available to the internal test group with the branch name visible in the Crashlytics artefact, e.g. build-645-make-a-space-rocket.

git flow feature publish make-a-space-rocket

Build notifications are posted in the corresponding channel in Slack, making this is a great way to get quick feedback from a select group of internal users. Internal integration testing Once a feature is complete, the developer merges it into the develop branch.

git flow feature finish make-a-space-rocket

Doing so will build and publish another internal artefact to Crashlytics, this time built from the develop branch and thus integrating all unreleased features. To easily distinguish it from the feature branches in Crashlytics we simply append a -develop label to its name.

Crashlytics releases

As builds from the develop branch are in fact candidates for the next public app release we use them regularly for internal beta testing.

External release candidates

Periodically, and once integration tests were successful, we initiate the public release cycle by creating a release branch for the desired version. We use semantic versioning and reserve the patch level for hotfixes. Therefore a new release always has a patch level of zero, as follows:

git flow release start 1.3.0

Release branches allow us to make final adjustments to the code and set a version number.

Pushing a release branch to the central repository will trigger the public release pipeline on NeverCode, which will cause a new version of the app be made available immediately to all registered beta users for Android and iOS respectively.

git flow release publish 1.3.0

We keep this branch open during the entire external testing phase, which enables us to incorporate feedback from external testers swiftly without interfering with the normal feature development workflow. Note that we do try to minimise commits (or rather pushes) to this branch, so that testers don’t get overwhelmed by a flurry of beta releases.

Public releases

The only thing left now, is to release the app for review in the corresponding app store. We keep the release branch open during the review phase as well, in case any last minute change comes in. A commit will automatically trigger a new external release candidate, which we can easily advance to the review stage again.

Once the new app version is approved, we release it in the app store and finally merge the release branch into the master and develop branches with the following command.

git flow release finish 1.3.0

This makes sure that all last minute fixes for the release make their way into the version control trunks.


Lastly, serious or time sensitive bug fixes are rolled out using Gitflow as well. The process is similar to a normal release, but for a hotfix we increment the version patch level each time.

git flow hotfix start 1.3.1

Pushing a hotfix will immediately generate a new external beta release, which can be advanced to app store review straight away after testing.

git flow hotfix publish 1.3.1

Once the app has passed review and is ready for release we merge the hotfix into master and develop.

git flow hotfix finish 1.3.1

The configuration

We’ve discussed Gitflow already, so let’s have a look at how NeverCode glues everything together for us. We define a project for each platform: Android and iOS.

NeverCode projects

Within each project we need two workflows: One for builds from the development branches to Crashlytics; the other from the release branches to the corresponding app store.

Within each workflow there are two important screens: Build, which defines what branches to monitor, and Publishing, which controls how and where the build artefact gets published.

Build settings

NeverCode workflow build settings

On the build configuration screen for the development workflow, set the Main Branch to “develop”, while you set the Watched branch pattern to a special pattern that matches feature and bugfix branches: [fb][eu][ag]*/*.

On the other hand, on the build configuration screen for the release workflow, set the Main Branch to “master”, while you set the Watched branch pattern to a pattern that matches release and hotfix branches: [rh][eo][lt]*/*.

Publishing settings

Next, on the Publishing screen in the workflow configuration, select Publish to Beta by Crashlytics in the development workflow, while enabling Publish to TestFlight Beta Testing in iTunes Connect in the release workflow. Do the same for the Android build, but selecting Publish to Google Play in the release workflow.

NeverCode workflow publishing settings

Watch your builds being published…

NeverCode iOS builds


This is the mobile delivery pipeline we use to develop Authentiq ID on Android and iOS.

In our workflow a mobile developer only needs to interact with Git, and we use NeverCode as the automation pipeline to trigger builds off a Git branch and ship the artefacts to the appropriate release channel: Crashlytics, TestFlight or Play Store.

As a bonus, we elegantly get hotfixes for free, instead of requiring separate procedures.

Try Authentiq on NeverCode

Or add it to your own website today!

Also, don’t forget to subscribe to our newsletter to keep up-to-date with everything passwordless.