Auto-incrementing Build Numbers in Xcode

Users and testers will find bugs you are sure you have already fixed. Sometimes they use the wrong version, sometimes your fix is not as good as you thought. Either way a tiny unique version number visible in the app can save you hours of work.

Incrementing the version number of your project for every small update is often not feasible, if it involves manual labor it just does not get done. Would it not be nice if Xcode just autoincremented a build number for you every time you build?

This can be done

There are dozens of solution to the problem available by Google. Unfortunately most do not work in both Xcode 3.2 and Xcode 4, and many more require a lot of hacking, even running external Perl or Python scripts. Using avgtool seems to be a major overkill for most use-cases. There must be an easier way, and there is.

What we want to do is to have the build number available in our Info.plist file, so that it can be read and displayed at run-time. And we also want Xcode to automatically increment this number for every build.

Add a key named CWBuildNumber to your Info.plist file, and set it to a sane start value, maybe “0”. You can load it at run-time with a short statement like:

NSString* buildNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CWBuildNumber"];

Both Xcode 3.2 and Xcode 4 allows to add a Run Script phase to any target. Unfortunately Xcode 3.2 and 4 run these scripts with different paths. PROJECT_DIR environment variable to the rescue! Secondly we want to rewrite the target’s source Info.plist file, not the file bundled with the application, so make sure to order the script phase before the Copy Resources phase. Then just add this tiny script phase to your target build:

buildNumber=$(/usr/libexec/PlistBuddy -c "Print CWBuildNumber" ${PROJECT_DIR}/MyApp-Info.plist)
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CWBuildNumber $buildNumber" ${PROJECT_DIR}/MyApp-Info.plist 


Happy developers, and happy tester. Maybe even happy users, if you choose to show the full version number including build number in the final product.

This Post Has 21 Comments

  1. ahlongxp

    Good you’re sharing this. I have been doing the similar thing in my recent projects. And it works well.

  2. Ric

    Fredrik, I’m new in this environment so pls give me some latitude.

    When I try to add a new key to my app’s info.plist I am confined to a set of Keys that are acceptable in a dropdown menu. This stops me from adding your CWBuildNumber Key.

    Then when I try to add a Run Script it wants me to use a file that I get to via finder, so what is the extension I use for this buildNumber script code ?

    Thank you very much for your helpful time here.


  3. Fredrik Olsson

    @Ric: You can type any key you want in the plist file by double clicking in the cell.

    Adding the script is not in a separate file. This description assumes you use Xcode 4.
    Selector the project item in the project browser, the main area of Xcode will have a list to the left with two headers “PROJECT”, and “TARGET”.
    Make sure your target is selected, the is now a list of tabs in the top on the main area labeled for example “Summary”, “Info”, “Build Settings”. The number of tabs changes with the type of target.
    Select the “Build Phases” tab, for a normal iOS app it have four expandlae items/phases in a list “Target Dependencies”, “Copy Bundle Resources”, “Compile Sources”, and “Link Binary With Libraries”.
    Select “Add Run Scrip” from the popup button with a plus in the lower right.
    Drag the added script phase above “Copy Bundle Resources” and paste the shell script into it.

  4. Tony

    Here is a solutions I created based on this one. Follow these steps to create an auto incrementing build number for CFBundleVersion and CFBundleShortVersionString

    1. Create a new key in your application PList file called CWAutoNumber of type number and set to your desired seed number (example: 12345).
    2. Create a new key in your application PList file called CWVersionNumber of type string and put in here the value you have in CFBundleVersion (example: 1.0).

    Put the following script in a Run Script build phase for your project target.

    autoNumber=$(/usr/libexec/PlistBuddy -c “Print CWAutoNumber” ${PROJECT_DIR}/MyApp-Info.plist)
    autoNumber=$(($autoNumber + 1))
    /usr/libexec/PlistBuddy -c “Set :CWAutoNumber $autoNumber” ${PROJECT_DIR}/MyApp-Info.plist
    versionNumber=$(/usr/libexec/PlistBuddy -c “Print CWVersionNumber” ${PROJECT_DIR}/MyApp-Info.plist)
    /usr/libexec/PlistBuddy -c “Set :CFBundleVersion $bundleVersion” ${PROJECT_DIR}/MyApp-Info.plist
    /usr/libexec/PlistBuddy -c “Set :CFBundleShortVersionString $bundleVersion” ${PROJECT_DIR}/MyApp-Info.plist

  5. Elliot


    Thanks for posting, this is the first I’ve come across that works with Xcode 4. However, I’d like to suggest one addendum:

    In the project I was trying to work with, I had moved the Info.plist file into another directory, so hard-coding the path wasn’t working. Luckily, there’s an environment variable for the location of the Info.plist file also, so by using the following path in your script, you can avoid this issue.



    buildNumber=$(/usr/libexec/PlistBuddy -c “Print CWBuildNumber” ${PROJECT_DIR}/${INFOPLIST_FILE})
    buildNumber=$(($buildNumber + 1))
    /usr/libexec/PlistBuddy -c “Set :CWBuildNumber $buildNumber” ${PROJECT_DIR}/${INFOPLIST_FILE}

    Thanks again for the post!

  6. huey

    Hey Frederik, when I tried this all I got was an error that said: “Print: Entry, “CWBuildNumber”, Does Not Exist” and “Command /bin/sh failed with exit code 1”

    Any ideas what might be going on?

    1. Fredrik Olsson

      I believe you forgot to add the CWBuildNumber key with an initial value to your info.plist file, or you misspelled it.

  7. yOOrek

    Thanks for this info. What I found is that in Xcode4, the App-Info.plist resides in ${PROJECT_DIR}/${PRODUCT_NAME}/${PRODUCT_NAME}-Info.plist. I got the same message as huey. Once I adjusted the path it all worked fine.

  8. Pierre-Jean Quilleré

    Why using CWBuildNumber when we can use CFBundleVersion?

    1. Fredrik Olsson

      You could use the minor version in CWBundleVersion, but v1.0.2318 still looks silly compared to v.1.0.1. I believe bundle version should only be used for released versions, the build number is for your testers.

  9. Brush

    Ok, I want to run this script in my run script phase:

    buildNumber=$(/usr/libexec/PlistBuddy -c “Print CWBuildNumber” ${PROJECT_DIR}/${PRODUCT_NAME}/${PRODUCT_NAME}-Info.plist)
    buildNumber=$(($buildNumber + 1))
    /usr/libexec/PlistBuddy -c “Set :CWBuildNumber $buildNumber” ${PROJECT_DIR}/${PRODUCT_NAME}/${PRODUCT_NAME}-Info.plist

    but I get this error:

    Unrecognized Command + 1: syntax error in expression (error token is “Command + 1”)
    Command /bin/sh failed with exit code 1

    So what’s wrong? Thx.

  10. Dominic

    i have the problem like Brush – any help?

  11. Azpiri

    I had the same problem like Brush and Dominic. If the path is different (like latest versions of xcode) or has spaces (directory or file names) the script doesn´t work.

    I have tried this alternative version of the script and works perfect even in those cases (just replace CFBundleVersion whatever you want to autoincrease):

    # Auto Increment Version Script
    buildNumber=$(/usr/libexec/PlistBuddy -c “Print CFBundleVersion” “${PROJECT_DIR}/${INFOPLIST_FILE}”)
    buildNumber=$(($buildNumber + 1))
    /usr/libexec/PlistBuddy -c “Set :CFBundleVersion $buildNumber” “${PROJECT_DIR}/${INFOPLIST_FILE}”

  12. P-Chan

    Thanks for pointing me to PlistBuddy! That tool enabled me to throw away some hairy shell-scripting for modifying plist files :)

  13. Greg

    Was getting the same error as Brush after using one of the examples cited in the comments (not Fredrick’s original). After tweaking the script for 10 minutes I realized copy/pasting the script from the web used “special” quotes instead of “plain old” quotes. Doh!

    So, double check your quotation marks.

    Thanks for the great post by the way.

Leave a Reply