Automatic Versioning for React Native Apps
Tags: react, reactnative, fastlane, version
Published: 2020-04-18 12:27:42

---
title: Automatic Versioning for React Native Apps
published: true
description: Don't do it manually.
tags: react,reactnative,fastlane,version
---

## Problem

You need to update your app's version to 1.0.0:

1\. You open up `android/app/build.gradle` to update the version and bump the build number.

2\. You do the same thing for iOS using Xcode because editing build configuration files directly is more error prone.

3\. You need to keep it all consistent, so you open up `package.json` and update the version so the reference to the version shown to the user from the JS side is correct. 

```js
import { version } from "./package.json"

console.log(version)
// 1.0.0
```

_I feel so productive and happy!_

Said no developer ever after going through that.

## Solution

The ideal experience is to update only a single version number. Here's what we're going to do:

1\. Use `npm version [patch|minor|major]` to handle the JS package version (see [semantic versioning](https://docs.npmjs.com/about-semantic-versioning)).

The JS version is our **source of truth**. Therefore, the Android and iOS versions should match whatever the `package.json` version is set to.

2\. Use fastlane to handle the Android and iOS sides.

> [fastlane](https://fastlane.tools/) is an amazing open source tool focused at automating Android and iOS tasks. It has a wide library of community developed plugins that can help us handle things like, _versioning_.

3\. Combine the above 2 steps into a single npm script.

### Steps

We will use a fresh React Native project as a starting point:

```bash
npx react-native init MyApp
```

Install fastlane if you do not already have it:

```bash
# Install the latest Xcode command line tools
xcode-select --install

# Install fastlane using RubyGems
sudo gem install fastlane -NV

# Alternatively using Homebrew
brew install fastlane
```

Set up a fastlane directory and create an empty fastfile:

```bash
cd MyApp
mkdir fastlane && cd fastlane 
touch Fastfile
```

We want to be able to run the `fastlane` command from the root of our React Native project. Therefore we will install our versioning plugins from the root directory:

```bash
cd ..

# Install plugins
fastlane add_plugin increment_version_name increment_version_code load_json
```

Say 'yes' if it asks about creating a gemfile.

The first two plugins are for handling the version, version code on android and the third one is for reading a JSON file (our `package.json`).

Next, we are going to add our fastlane scripts. Copy the following to the fastfile at `fastlane/Fastfile`.

```ruby
  desc 'Android: Increment versionCode and set versionName to package.json version.'
  package = load_json(json_path: "./package.json")

  private_lane :inc_ver_and do
    increment_version_code(
      gradle_file_path: "./android/app/build.gradle",
    )

    increment_version_name(
      gradle_file_path: "./android/app/build.gradle",
      version_name: package['version']
    )
  end


  desc 'iOS: Increment build number and set the version to package.json version.'
  private_lane :inc_ver_ios do
  package = load_json(json_path: "./package.json")

    increment_build_number(
      xcodeproj: './ios/' + package['name'] + '.xcodeproj'
    )
    increment_version_number(
      xcodeproj: './ios/' + package['name'] + '.xcodeproj',
      version_number: package['version']
    )
  end


  desc 'Bump build numbers, and set the version to match the pacakage.json version.'
  lane :bump do
    inc_ver_ios
    inc_ver_and
  end
```

Next we are going to add the following scripts to our package.json for automatic patch, minor and major version bumps:

```json{11-13}
{ 
  "name": "MyApp",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint .",
    "bump-patch": "npm version patch --no-git-tag-version && bundle exec fastlane bump",
    "bump-minor": "npm version minor --no-git-tag-version && bundle exec fastlane bump",
    "bump-major": "npm version major --no-git-tag-version && bundle exec fastlane bump",
},
```

The first part of the command will upate the JS package version without making a commit to the git repo. The second part will execute the fastlane bump command, which will automatically bump the android and iOS build numbers and update the version to match the JS side.

```bash
# npm
npm run bump-patch  

# yarn
yarn bump-patch
```


![Version Bump Gif](https://media0.giphy.com/media/f8i5lrH2aBA66eP4Z8/giphy.gif)

--------------------

PS: I'm maintaining a React Native [template with a lot of goodies](https://github.com/osamaq/react-native-template/) like the one in the article.