Convention-Based Creation (create_from)
Generating Resources from Property Values and Data Lists
The create_from directive inside a [[create_resource]] block provides two powerful convention-over-configuration
patterns for resource creation.
create_from = { property = "..." }— creates resources from the values of a property on theorigin_resourcecreate_from = { list = "..." }— creates resources by iterating over an abstract data list defined in the header
Both patterns make the iterated item available as {{ value }} inside templates.
Pattern 1: Creating from a Property Value
When a property contains a list (an array or a comma-separated string), create_from creates one resource for
each item. The property name becomes the default resource type, and the property value becomes the default
primary key (name). Both can be overridden.
data/assets/application.csv
name,service
zabbix,"monitoring, alerting"
data/models/application_services.toml
origin_resource = "application"
[[create_resource]]
create_from = { property = "service" }
relation_type = "PROVIDES"
name = "svc-{{ value | upper }}"
[create_resource.properties]
category = "Operations"
Result: Two service resources are created — svc-MONITORING and svc-ALERTING — each linked to the
zabbix application via a PROVIDES relationship.
Template Variables Available in create_from
Inside the [[create_resource]] block during a create_from = { property = "..." } expansion, the template context contains:
| Variable | Type | Description |
|---|---|---|
value |
String |
The current element value (e.g. "monitoring"). |
property.value |
String |
Alias for value. |
property.index |
Integer |
0-based iteration index (0, 1, 2, …). Useful for array indexing, naming, and procedural calls. |
origin_resource |
Map |
Properties of the origin resource currently being expanded. |
origin_resource_counter |
Integer |
Counter incrementing once per origin resource processed. |
Note: Tera’s built-in
loop.index/loop.index0variables are not present increate_fromiterations. The iteration is handled directly by the rescile importer engine, which providesproperty.index. For per-origin CIDR splits, select the matching subnet insideproperties, for example{{ origin_resource.cidr | lib(path="network.rhai", function="cidr_split_n", n=4) | nth(n=property.index) }}. Test with two origins that have different CIDRs; a shared top-level value would give both the same plan.
Type Resolution Priority
The resource type for items created by create_from is resolved in this order (highest priority first):
- The
askey inside thecreate_fromblock:create_from = { property = "service", as = "platform_service" } - The top-level
resource_typedirective - The property name itself (e.g.,
"service")
Deriving from a Related Node (property_origin and relation_origin)
Use property_origin to read the source property from a related node instead of the origin_resource. Use
relation_origin to control where the new relationship starts from.
Goal: From a subscription, find its related application, read its service property, and create service
resources linked back to the subscription (not the application).
origin_resource = "subscription"
[[create_resource]]
property_origin = "application" # Read the property from the related application
create_from = { property = "service" }
relation_type = "USES"
relation_origin = "origin_resource" # Start the new relation from the subscription
Important: For
property_originto find the related resource, the referencing column on theorigin_resourcemust remain a plain string property. If the column name matches a resource type/asset filename (such asapplication), the asset importer will auto-link it and remove the scalar property. In that case, prefix the header with_(e.g.,_application) to suppress auto-linking while keeping the value readable.
property_origincurrently follows a single relationship and, if the property contains multiple values, only uses the first one.
Pattern 2: Creating from a Data List
When used with list, create_from iterates over a variable defined in the file header. A normal literal or
globally resolved list is ideal for bootstrapping a graph from configuration data rather than from existing graph
resources. When origin_resource is omitted, the list is resolved once and iterated globally; no
origin_resource is available during that global list iteration.
Static header lists with an origin
When the model does declare an origin_resource and the header list is a static value (a literal array or a
globally resolved header variable, not a json! or external! binding), rescile runs a nested loop: once per
matching origin resource, then once per list item. Inside the inner loop, origin_resource is available in
templates, match_on filters the origins, and relation_type links each created resource to its origin.
origin_resource = "application"
instance_list = ["test", "dev"]
[[create_resource]]
create_from = { list = "instance_list", as = "compute" }
relation_type = "DEFINED_BY"
name = "{{ origin_resource.name }}-{{ value }}-instance"
match_on = [{ property = "class", value = "compute" }]
Result: For every application with class = compute, one compute resource per list item is created,
each linked to its application via DEFINED_BY. Resources that render the same (resource_type, name) are
deduplicated and receive a relation from each matching origin.
The same applies to Jsonnet models that export the list as a root field:
{
instance_list: ['test', 'dev'],
} + rescile.createResource(
origin='application',
createFrom=rescile.createFromList('instance_list'),
resourceType='compute',
relationType='DEFINED_BY',
name='{{ origin_resource.name }}-{{ value }}-instance',
)
# data/models/providers.toml
# No origin_resource is defined.
provider_list = ["aws", "azure", "gcp"]
[[create_resource]]
create_from = { list = "provider_list", as = "provider" }
name = "cloud-{{ value }}"
[create_resource.properties]
short_name = "{{ value | upper }}"
category = "IaaS"
Result: Three provider resources are created: cloud-aws, cloud-azure, and cloud-gcp.
Origin-dependent dynamic JSON lists
When the header list is a templated json! binding that transitively depends on origin_resource, rescile infers
a nested iteration. It resolves the selected file separately for each origin, then exposes each list item as
value while keeping the current origin_resource available:
origin_resource = "compute"
environment_name = { "function!" = "{{ origin_resource.environment | lower }}" }
providers = { "json!" = "{{ environment_name }}-providers.json", jmespath = "providers" }
[[create_resource]]
create_from = { list = "providers" }
resource_type = "login"
relation_type = "USES_PROVIDER"
name = "{{ origin_resource.name }}-{{ value.name }}-login"
The JSON path may use global values such as params instead. In that case rescile resolves the list once and keeps
the normal global list behavior — even when the model declares an origin_resource. The path cannot depend on
value, because rescile must load the list before the first value exists.
List scope rules
| List source | origin_resource declared? |
Execution |
|---|---|---|
| Static header value (literal array, globally resolved variable) | No | Once, globally; no origin_resource in templates; relation_type ignored |
| Static header value | Yes | Once per matching origin, then per item; origin_resource available, match_on and relation_type honored |
Dynamic json! binding with global dependencies |
Either | Once, globally |
Dynamic json! binding with transitive origin_resource dependency |
Yes | Once per origin, then per item; both variables available |
external! result |
Either | Once, globally; arguments must not reference origin_resource or value |
Comparison of Creation Patterns
| Feature | Direct Derivation | From Property | From Global List | From Static List with Origin | From Origin-Dependent JSON List |
|---|---|---|---|---|---|
| Trigger | Existence of a graph resource | Values inside an origin property | A globally resolved header list | A static header list plus a declared origin | A dynamic header list selected by each origin |
origin_resource available? |
Yes | Yes | No | Yes | Yes |
value available? |
No | Yes | Yes | Yes | Yes |
| Cardinality | 1:1 | 1:N per origin | N resources | 1:N per origin | 1:N per origin |
| Default resource type | resource_type (required) |
Property name | List name | List name | List name |
| Default name | name template (required) |
Property value | List item value | List item value | List item value |
| Primary use case | Structural relationships | Dependencies stored on the graph | Bootstrapping from global configuration | Shared per-origin expansion data | Per-origin local lookup data |
For the full [[create_resource]] directive reference, see
[[create_resource]] Reference.