A Blue document is structured content selected from a graph. It may be as small as a single scalar value or as large as a business process with embedded child documents and contracts. The same language rules apply in both cases: nodes have payloads, metadata, type references, schema constraints, and identity.
This page explains the content model before runtime processing. Timelines, operations, workflows, and BEX matter later, but they all sit on top of the same document and type system.
A Blue document is a rooted slice of a Blue graph. The root can be an object, list, scalar, or pure reference. Most authored examples use YAML objects because they are easier to read:
1name: Counter2counter: 0
This document has an object root with two ordinary fields. After preprocessing, counter: 0 is understood as an integer scalar value in the Blue node model.
A node has one payload kind:
| Payload kind | Example | Notes |
|---|---|---|
| Scalar | counter: 0 | Text, integer, double, and boolean scalar values are inferred during baseline preprocessing when no explicit type is provided. |
| Object fields | price: { amountMinor: 49900, currency: PLN } | Most business documents are object nodes. |
| List items | items: [hotel, restaurant] | List positions are content. Empty positions are not silently deleted. |
| Pure reference | blueId: <BlueId> | The node is exactly a reference to content addressed by BlueId. |
Nodes can also carry Blue language metadata. Common metadata fields include name, description, type, schema, itemType, keyType, valueType, mergePolicy, contracts, and blueId.
That last sentence is easy to skim past, but it is important. In Blue, metadata is still content. A canonical type node's description, for example, can be identity-bearing when it defines the type's semantics. Do not treat canonical type descriptions like website copy unless the registry intends them to be editorial text outside the identity-bearing node.
In many systems, schemas and data live in different worlds. Blue does not make that split. A type is a Blue node, and a document can point to it.
Here is a reusable money amount type:
1name: Money Amount2description: Amount in minor currency units.3amountMinor:4 type: Integer5 schema:6 minimum: 07currency:8 type: Text9 schema:10 minLength: 311 maxLength: 3
Here is a document that uses it:
1name: Package Price2type:3 blueId: <MoneyAmountBlueId>4amountMinor: 499005currency: PLN
The type field says: this node must conform to the referenced type. During resolution, a processor uses a node provider to load the referenced content, merge the inherited type information with the instance, and validate the result.
The instance does not need to repeat every inherited detail. It only supplies the values that make this specific node different from the type definition.
You will often see examples like this:
1type: Integer
That is not the canonical identity-bearing form. It is source authoring sugar. During preprocessing, core type aliases such as Integer, Text, Double, Boolean, Dictionary, and List are replaced by canonical type references from the Blue type registry.
When you define your own aliases, declare them explicitly through the root blue directive:
1blue:2 imports:3 MoneyAmount:4 blueId: <MoneyAmountBlueId>56name: Package Price7type: MoneyAmount8amountMinor: 499009currency: PLN
After preprocessing, MoneyAmount in a type position becomes:
1type:2 blueId: <MoneyAmountBlueId>
This keeps source pleasant without making portable identity depend on hidden local names.
A pure BlueId reference is the entire node:
1blueId: <MoneyAmountBlueId>
Do not add sibling fields to a pure reference:
1# Invalid as a pure reference shape2blueId: <MoneyAmountBlueId>3amountMinor: 499004currency: PLN
If you want a value that is typed by a referenced type, put the reference under type:
1type:2 blueId: <MoneyAmountBlueId>3amountMinor: 499004currency: PLN
The distinction avoids an ambiguity that has caused problems in many data systems: is this object the referenced thing, or is it a new local thing with a related type? Blue makes the answer structural.
Blue's type system is built around compatibility. A more specific type can add fields and compatible constraints, but it cannot contradict the parent.
Start with a general product:
1name: Product2sku:3 type: Text4 schema:5 required: true6 minLength: 37price:8 amountMinor:9 type: Integer10 schema:11 minimum: 012 currency:13 type: Text14 schema:15 minLength: 316 maxLength: 3
Now specialize it into an offer:
1name: Offer2type: Product3kind: Offer4status:5 type: Text6 schema:7 enum: [draft, active, retired]8seller:9 name:10 type: Text
Then specialize further into a package offer:
1name: Weekend Package Offer2type: Offer3offerKind: package4included:5 hotel:6 title:7 type: Text8 restaurant:9 title:10 type: Text
Every Weekend Package Offer is also an Offer. Every Offer is also a Product. That statement should remain true after resolution. Blue enforces it by rejecting incompatible overlays.
If Offer fixes kind: Offer, a child cannot change it to kind: Voucher:
1# Invalid: contradicts inherited fixed value2name: Broken Package Offer3type: Offer4kind: Voucher
Fixed values are useful because they give type hierarchies discriminators without relying on external enum mapping code. But fixed values only work if descendants cannot quietly override them.
If Product.price.amountMinor is an integer, a child cannot turn it into text:
1# Invalid: inherited field type is Integer2name: Broken Product3type: Product4price:5 amountMinor:6 type: Text
A child may refine a field with a compatible subtype or additional constraints. It may not weaken the field so existing Product consumers would be surprised.
Schema constraints are attached through schema:
1name: SKU2value:3 type: Text4 schema:5 minLength: 36 maxLength: 32
A more specific type can add a stricter compatible constraint:
1name: Merchant SKU2type: SKU3value:4 schema:5 minLength: 8
The effective value must satisfy both constraints. If a child adds an incompatible constraint, resolution fails. Blue does not let the child pretend the inherited rules disappeared.
Useful schema keywords include required, minLength, maxLength, minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, minItems, maxItems, uniqueItems, minFields, maxFields, and enum.
Fields are optional by default. To require a field, attach schema.required: true to the child field declaration:
1name: Merchant Order2kind: Order3orderKind:4 type: Text5 schema:6 required: true7confirmation:8 status:9 type: Text10 schema:11 required: true12 enum: [pending, confirmed, rejected]
A metadata-only declaration does not satisfy the requirement. The resolved descendant must supply meaningful content for the field. This matters for workflow documents, where a field may be declared in the type but not filled until an operation is delivered.
Source is what you author. Resolved view is what processors use to understand inherited fields, fixed values, schema constraints, and referenced types.
Given this type:
1name: Confirmation State2status:3 type: Text4 schema:5 enum: [pending, confirmed, rejected]
And this instance:
1blue:2 imports:3 ConfirmationState:4 blueId: <ConfirmationStateBlueId>56type: ConfirmationState7status: confirmed
The resolver loads <ConfirmationStateBlueId>, expands the type information, validates that confirmed is one of the allowed values, and produces a resolved view where both the inherited constraints and instance value are available.
The canonical identity input may be more compact than the resolved view. If a field is fully inherited and does not need to be repeated for identity, canonicalization can omit it. That is why raw source comparison is not the right way to compare Blue documents.
Blue lists are not just arrays that can be cleaned casually. Position is content. If a source list contains null or an empty object as an element, preprocessing normalizes that position to a placeholder rather than deleting it:
1items:2 - hotel3 - null4 - restaurant
Normalizes to a list with an explicit empty position:
1items:2 - hotel3 - $empty: true4 - restaurant
That placeholder affects identity. It is not the same as removing the item and shifting later indices.
List overlays also have controls for inherited lists. A $previous anchor can state which inherited prefix is being extended, and $pos can refine a specific inherited position when the list's merge policy allows positional overlays:
1items:2 - $previous:3 blueId: <InheritedItemsBlueId>4 - $pos: 15 value: upgraded dinner6 - value: late checkout
Use these controls only when you are intentionally working with inherited list content. Ordinary business documents usually do not need them at first. They become important when a type or template contributes list content and a descendant wants to refine it without restating the entire list.
You will see a contracts map in processable documents:
1contracts:2 ownerChannel:3 type: Coordination/Timeline Channel4 timelineId: counter-demo56 increment:7 type: Coordination/Operation8 channel: ownerChannel
From the language perspective, contracts is a reserved field that affects document content and identity like any other field. The runtime meaning is defined by the Contracts and Processor specification and by packages such as Coordination.
This separation is useful. The Blue Language can define how contracts participates in content, resolution, and identity without hard-coding every possible contract runtime into the language.
In the weekend package example, the package order embeds a PayNote and merchant order snapshots:
1embeddedDocs:2 packagePayNote:3 type: PayNote/PayNote4 kind: PayNote5 orders:6 hotelOrder:7 kind: Order8 orderKind: hotel9 restaurantOrder:10 kind: Order11 orderKind: restaurant
Language-wise, these are child nodes. Runtime-wise, contracts such as Core/Embedded Node Channel and Core/Process Embedded let events from those child scopes influence parent or sibling workflows.
Keep those two views separate. Embedding is not a magical database join. It is content in the parent document, with runtime contracts deciding how child processing is observed.
When authoring Blue documents, follow these rules:
type to make structure explicit. Use pure blueId only when the node is exactly a reference.The rest of the runtime builds on these rules. A workflow can only be deterministic if the document it processes has deterministic structure and identity.