BuildTargetGroup, BuildTarget: the difference between the two

In multiple entries in the documentation, use of the enumerations BuildTargetGroup and BuildTarget is confusing as both seem to be very similar. In methods like EditorUserBuildSettings.SwitchActiveBuildTarget(buildTargetGroup, buildTarget), or even BuildPipeline.BuildPlayer, the two are often merely described as "the build target" or "the build target group", without actually explaining what the two individually mean.

To my understanding, the BuildTargetGroup is used as the target you switch to in build settings, like PC/Mac/Linux (BuildTargetGroup.Standalone), and the BuildTarget the actual executable package which you'd build to using Ctrl/Cmd-B. However, this is not accurately described anywhere in the docs. Also, Unity expects to get two similar enums, like BuildTargetGroup.Android and BuildTarget.Android, but this does not restrict the developer to mix them up: which led to very odd results, debunking my theory.

For instance, I wanted to see the results (5.6.1f1, Win64) when executing this method, knowing that Unity would probably dislike it:
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.StandaloneWindows64);
This led to the result that my editor swapped to Standalone, not Android as I expected. The editor threw an error regarding the attempt to emulate OpenGL ES 3.0 while being on a platform which doesn't support it.
When attempting Build and Run short after, the editor immediately swapped to Android again and built as expected.


I'll post this into the docs team list of issues. Can't say how quickly documentation will be changed to make this more clear.

Would you be able to post an answer here with a quick explanation please :)

As I understand it, when you select any of the targets in Build Settings, you technically select a BuildTargetGroup, i.e. Standalone. If that target supports a variety of other platforms, like Standalone, you pick the specific build target you intend to use, like BuildTarget.StandaloneWindows, .OSX*, or Linux. It's usually depicted as another dropdown or two in the Build Settings window.

1 Like

I made a simple converter for personal use. That way I only define BuildTarget
Note that I didn't include obsolete BuildTargetGroup

    static BuildTargetGroup ConvertBuildTarget(BuildTarget buildTarget)
        switch (buildTarget)
            case BuildTarget.StandaloneOSX:
            case BuildTarget.iOS:
                return BuildTargetGroup.iOS;
            case BuildTarget.StandaloneWindows:
            case BuildTarget.StandaloneLinux:
            case BuildTarget.StandaloneWindows64:
            case BuildTarget.StandaloneLinux64:
            case BuildTarget.StandaloneLinuxUniversal:
                return BuildTargetGroup.Standalone;
            case BuildTarget.Android:
                return BuildTargetGroup.Android;
            case BuildTarget.WebGL:
                return BuildTargetGroup.WebGL;
            case BuildTarget.WSAPlayer:
                return BuildTargetGroup.WSA;
            case BuildTarget.Tizen:
                return BuildTargetGroup.Tizen;
            case BuildTarget.PSP2:
                return BuildTargetGroup.PSP2;
            case BuildTarget.PS4:
                return BuildTargetGroup.PS4;
            case BuildTarget.PSM:
                return BuildTargetGroup.PSM;
            case BuildTarget.XboxOne:
                return BuildTargetGroup.XboxOne;
            case BuildTarget.N3DS:
                return BuildTargetGroup.N3DS;
            case BuildTarget.WiiU:
                return BuildTargetGroup.WiiU;
            case BuildTarget.tvOS:
                return BuildTargetGroup.tvOS;
            case BuildTarget.Switch:
                return BuildTargetGroup.Switch;
            case BuildTarget.NoTarget:
                return BuildTargetGroup.Standalone;

When you are thinking that the above is confusing, bad documented, etc., try this:

var a = BuildTargetGroup.iOS;
var b = a;

"b" is equal to ".iPhone"

Bug? Any ideas why? Meaning? Background? Documentation?

Because iPhone is the exact same value as iOS, but no longer in use. They usually don't remove values as such, only tell the user they're obsolete and under the hood it handles it regardless.

Kidding me, or?
Changing a value at run time is a total different thing compared to displaying a hint during development that this or that is obsolete.
This behavior is ridiculously!
And: ".iPhone" is obsolete NOT ".iOS"!
So when they change a value without any developer interaction at run time, which is a no go at all, they should change it from ".iPhone" to ".iOS" and not the other way around.

Why they should never change a value?
Think about assert/unit tests ...

Let me refer to In this source file you will find that BuildTargetGroup.iOS == BuildTargetGroup.iPhone, as it's the characteristic of a C# enum.

1 Like

In Unity 2017.2, probably more recent versions too, there exists built-in functionality for the conversion:

BuildTargetGroup BuildPipeline.GetBuildTargetGroup(BuildTarget target);

You may be able to cast them like this: = (BuildTarget)9; 
buildPlayerOptions.targetGroup = (BuildTargetGroup)4;
1 Like


1 Like

These are two enums that serve exactly the same purpose but with different granularity under different circumstances. The whole build system is a mess, go figure: build target, build target group, build subtarget, build options, editor build settings, build settings, editor user build settings, player settings. Some have explicit set/get, some go through string-based funky SetPlatformSettings. Some are named in API same as UI, some are completely different. Some are stored in ProjectSettings, some are stored in Library (that Unity doesn't recommend versioning but what you gonna do if you want deterministic builds). Some API calls are ignored when Unity is in an "inconvenient" busy state compiling stuff. Some package manager packages are not really packages and require manual steps to be resolved (I'm looking at you TextMeshPro with your Import Essential Assets). This is all legacy of one-project-one-game principle laid as a foundation years ago that we still suffer through. Somebody needs to decouple editor from compiler, like it's done in many development platforms. It's quite a show really.


Still suffering from this. It would be great if this could be cleaned up!



We can't build iOS in batch mode because of this bug... It consistently writes BuildTargetGroup as "iPhone" no matter how we cast it, and it breaks the build.