Nested Types
This example defines an Order and gives it a nested Status type for tracking whether it has shipped. Keeping the two types in the same module lets callers import Order once and refer to its status as Order.Status.
Here is the type module in Order.roc:
Order := { item : Str, status : Status }.{ Status := [Pending, Shipped].{ is_eq : _ } new : Str -> Order new = |item| { item, status: Pending } ship : Order -> Order ship = |order| { ..order, status: Shipped } }
Order is a record that holds an item and its status. Inside its associated block, Status defines the states that an order can have, alongside methods for creating and shipping an order.
The app can use both types through the same import:
import Order order = Order.new("Roc mug") shipped = order.ship() status : Order.Status status = shipped.status expect order.status == Order.Status.Pending expect status == Order.Status.Shipped expect shipped.item == "Roc mug"
This grouping gives the status a clear owner: it is an order status, rather than a general-purpose Status type. Since a type module exposes one top-level type, nesting also lets that type’s public API include related types without putting each in a separate module.
Nesting is independent of recursion. The Recursive Types example shows types that refer to themselves and each other without an enclosing type.
Output
Run this from the directory that has main.roc in it:
$ roc test main.roc All (3) tests passed in 9.5 ms.
Validated with Roc nightly-2026-10-29-a0a9fc2.