Skip to main content

Target Definitions

Inside a Build class, you can define your build steps as Target properties. The implementation for a build step is provided as a lambda function through the Executes method:

Build.cs
class Build : NukeBuild
{
public static int Main() => Execute<Build>();

Target MyTarget => _ => _
.Executes(() =>
{
Console.WriteLine("Hello!");
});
}

Dependencies​

Specifying dependencies is essential to let targets run in a meaningful and predictable order. There are 3 different types of dependencies, each of them can be defined from both directions.

Define that target A must run before target B unless A is skipped:

Build.cs
class Build : NukeBuild
{
Target A => _ => _
.DependentFor(B) // Choose this...
.Executes(() => { });

Target B => _ => _
.DependsOn(A) // ...or this!
.Executes(() => { });
}
tip

When choosing a direction, you should ask yourself which target should know about the existence of the other. For instance, should a Release target trigger a Tweet target? Or should a Tweet target be triggered by a Release target?

caution

Dependencies between targets are ONLY defined between the individual targets and NOT through their positions in a dependency call. The following examples illustrate the difference between the partial and total order of targets:

The execution is nondeterministic between A->B->C and B->A->C. This isn't necessarily problematic, but something to be aware of. In particular, it allows different targets to run in parallel (currently only in compatible CI/CD environments).

Build.cs
class Build : NukeBuild
{
Target A => _ => _
.Executes(() => { });

Target B => _ => _
.Executes(() => { });

Target C => _ => _
.DependsOn(A, B)
.Executes(() => { });
}

Conditional Execution​

Apart from skipping targets manually, you can also programmatically decide whether a target should be skipped. Depending on the use-case, you can choose between dynamic and static conditions.

Define a condition that is checked right before target B executes:

class Build : NukeBuild
{
readonly List<string> Data = new();

Target A => _ => _
.Executes(() => { /* Populate Data */ });

Target B => _ => _
.DependsOn(A)
.OnlyWhenDynamic(() => Data.Any())
.Executes(() => { });
}
tip

When a condition is not met, the skip reason is created from the boolean expression. For more complex conditions, you can extract the logic into a separate method or property to make the message more readable.

Requirements​

You can define target requirements that are checked right at the beginning of the build execution before any other targets are executed:

class Build : NukeBuild
{
Target A => _ => _
.Requires(() => IsServerBuild)
.Executes(() => { });
}
note

Target requirements are an important aspect to achieve a fail-fast behavior. Preceding targets won't waste any execution time only to discover that a condition that was known right from the beginning was not met.

tip

When a requirement is not met, the exception message is created from the boolean expression. For more complex requirements, you can extract the logic into a separate method or property to make the message more readable.

Failure Handling​

Not every failing target should completely stop the build. Targets that are not essential can allow to continue the execution for other targets are important to run even if another target has failed. For these use-cases, you can configure the failure handling.

Define that execution continues after target A throws:

class Build : NukeBuild
{
Target A => _ => _
.ProceedAfterFailure()
.Executes(() =>
{
Assert.Fail("error");
});

Target B => _ => _
.DependsOn(A)
.Executes(() => { });
}

Unlisting Targets​

It is good practice to follow the single-responsibility principle when implementing targets. However, you may not want to expose every target through the build help text. For cases like this, you can un-list a target:

class Build : NukeBuild
{
Target A => _ => _
.Unlisted()
.Executes(() => { });
}