diff --git a/docs/src/defining_sequence.md b/docs/src/defining_sequence.md
index 04e494b14814c9a795d0c9fa07fddd4815d5f7cd..cc28e3f7516b2485eeaf4ed1337092e6875954c9 100644
--- a/docs/src/defining_sequence.md
+++ b/docs/src/defining_sequence.md
@@ -13,10 +13,10 @@ This name will have to be unique.
 
 The next step is to define the sequence constructor:
 ```julia
-function DiffusionSpinEcho(; scanner=DefaultScanner, parameters..., variables...)
+function DiffusionSpinEcho(; scanner=DefaultScanner, parameters..., vars...)
     build_sequence(scanner) do
         (g1, g2) = dwi_gradients(...)
-        return Sequence([
+        seq = Sequence([
             :excitation => excitation_pulse(...),
             nothing,
             :gradient => g1,
@@ -26,7 +26,10 @@ function DiffusionSpinEcho(; scanner=DefaultScanner, parameters..., variables...
             g2,
             nothing,
             :readout => readout_event(...),
-        ], name=:DiffusionSpinEcho, variables...)
+            nothing,
+        ], name=:DiffusionSpinEcho, vars...)
+        add_cost_function!(variables.duration(seq[6]) + variables.duration(seq[7]))
+        return seq
     end
 end
 ```
@@ -42,6 +45,7 @@ The crucial part here are the individual parts used to build the sequence, defin
     :gradient2 => g2,
     nothing,
     :readout => readout_event(...),
+    nothing
 ]
 ```
 
@@ -49,6 +53,17 @@ We can see that this sequence is built in order by an excitation pulse, some unk
 
 Some of these components have been given specific names (e.g., `:excitation => ...`). This is optional, but can be useful to refer to individual components. There are [helper functions](@ref helper_functions) available to create these components.
 
+After creating the sequence object, we can now add secondary objectives to the cost function (using [`add_cost_function!`](@ref)).
+In this example, we have:
+```julia
+add_cost_function!(variables.duration(seq[6]) + variables.duration(seq[7]))
+```
+If we check the order of the sequence component, we see that this minimises the sum of the duration of the second gradient and the wait block before this gradient.
+This cost function has been added to maximise the time between the second gradient and the readout (and hence minimise the effect of eddy currents on the readout).
+Note that this is a secondary cost function that will only take effect if it does not interfere with any user-defined constraints and cost functions (see [sequence optimisation](@ref sequence_optimisation)).
+Some secondary cost functions will be automatically defined for you within the individual components (e.g., a trapezoidal gradient has a secondary cost function to maximise the slew rate).
+There is even a tertiary cost function, which minimises the total sequence duration.
+
 The next step is to define [summary variables](@ref variables) that the user can constrain when setting up a specific instance of this sequence:
 ```julia
 @defvar begin
diff --git a/docs/src/sequence_optimisation.md b/docs/src/sequence_optimisation.md
index b3469fd4574e8ecafb07f2aed77e0a55d52c5eb8..0ab0233bdcc45e99a55330c3622fd5980e74b5f1 100644
--- a/docs/src/sequence_optimisation.md
+++ b/docs/src/sequence_optimisation.md
@@ -11,6 +11,10 @@ In addition to the user-defined constraints, this optimisation will also take in
 Internally, MRIBuilder will then optimise the `BuildingBlock` free parameters to match any user-defined constraints and/or objectives.
 This optimisation uses the [Ipopt](https://github.com/coin-or/Ipopt) optimiser accessed through the [JuMP.jl](https://jump.dev/JuMP.jl/stable/) library.
 
+In addition to any user-defined objectives, the developer might also define secondary objectives (e.g., manimise the total sequence duration). 
+These objective functions will only be considered if they do not affect the result of the user-defined primary objective.
+More details on these developer-defined secondary objectives can be found in the section on [defining new sequences](@ref defining_sequences)
+
 ## [Summary variables](@id variables)
 All variables are available as members of the [`variables`](@ref) structure.
 ```@meta
diff --git a/src/variables.jl b/src/variables.jl
index 76184d4b2c94e7385cf5911e4c8c5cebb7ca3e9e..b8d9b85fe448f4404413a9ae9788832a16f33da9 100644
--- a/src/variables.jl
+++ b/src/variables.jl
@@ -462,6 +462,8 @@ Terms added at a lower level will be optimised before any terms with a higher le
 
 By default, the term is added to the `level=2`, which is appropriate for any cost functions added by the developer,
 which will generally only be optimised after any user-defined cost functions (which are added at `level=1` by [`add_simple_constraint!`](@ref) or [`set_simple_constraints!`](@ref).
+
+Any sequence will also have a `level=3` cost function, which minimises the total sequence duration.
 """
 function add_cost_function!(func, level=2)
     push!(GLOBAL_MODEL[][2], (Float64(level), func))