---
title: "dataType (asset type)"
description: "A dataType is a user-authored typed-data contract: it declares a set of fields — names, types, constraints, defaults — that any bound .data instance must satisfy. A contract can carry an optional…"
section: "Types"
slug: "types-datatype"
canonical: "https://origozero.ai/docs/types-datatype"
updated: "2026-07-31T07:12:26.549038753+00:00"
tags: ["asset-type", "reference"]
---

# dataType (asset type)

## When to use one

- You want a typed, validated configuration shape (a weapon's damage /
  fire mode / recoil profile, a quest's objectives, a loot table's
  entries) that many `.data` instances can be authored against.
- You want field-level validation (required, numeric ranges, enums,
  references to other assets or data instances) enforced the same way
  everywhere the contract is used.
- You want shared structure across related contracts without
  duplicating field declarations — `extends` factors common fields
  into a parent contract.

If you only need a snapshot of one component's properties, use a
`.preset` instead. If you need executable shared logic rather than
typed configuration, use a `.module`.

## Where it lives

- Source: `/zero/source/.../<Name>.dataType/`
- Identity: `<Name>` (the `.dataType` suffix strips).
- Folder shape:
  - `schema.yaml` — the field declaration (`fields:`, optional
    `extends:`). **Required.**
  - `README.md` — instance documentation: what the contract models,
    what each field means. **Required.**
  - `.metadata` — description + tags for search. **Required.**
  - `behavior.luau` — optional ref methods this contract's `.data`
    instances expose beyond the built-in `:contract` / `:satisfies` /
    `:validate` surface.

## How to create one

```luau
asset.create("dataType", "<Name>")
-- Creates: /zero/source/<Name>.dataType/
--   schema.yaml   (empty `fields:` scaffold)
--   README.md     (instance README template)
--   .metadata     (empty description/tags — fill both to publish)
```

Then edit `schema.yaml` to declare the contract's fields.

## `schema.yaml` field-spec vocabulary

```yaml
extends: "item"           # optional: parent contract identity
fields:
  damage:
    type: number
    required: true
    min: 0
    max: 100
  fireMode:
    type: string
    enum: ["semi", "burst", "auto"]
    default: "semi"
  muzzle:
    type: vec3
    default: [0, 0, 0]
  tint:
    type: color             # "#rrggbb"/"#rrggbbaa" or {r,g,b[,a]}
  fireSound:
    type: assetRef
    assetType: soundClip     # required for assetRef fields
  recoil:
    type: dataRef
    contract: recoilProfile  # required for dataRef fields
    required: true
  falloff:
    type: array
    items:
      type: struct
      fields:
        distance: { type: number }
        multiplier: { type: number }
```

Field types: `number`, `string`, `boolean`, `vec3`, `color`, `assetRef`,
`dataRef`, `array`, `struct`.

- `required` — a boolean; a field with a `default` is never "missing"
  even when `required` is set.
- `default` — must itself satisfy the field's own constraints (checked
  at declaration time).
- `min` / `max` — apply only to `number` fields.
- `enum` — apply only to scalar fields (`number` / `string` /
  `boolean`); the value must equal one of the listed entries.
- `assetRef` — needs an `assetType`; validated against
  `asset.resolve(identity, assetType)`.
- `dataRef` — needs a `contract`; validated against whether the
  referenced `.data` instance's contract chain includes it
  (`:satisfies`).
- `array` — needs an `items` field spec every element must satisfy.
- `struct` — needs a `fields` map of nested field specs; struct values
  reject unknown keys the same way top-level values do.

## `extends`

A contract may declare `extends: "<parentContract>"` to inherit the
parent's fields. The child adds new fields — it never redeclares a
field the parent (or any ancestor) already declared; doing so is a
schema error. Behavior is optional at every level: a contract may
carry `behavior.luau` or not regardless of whether its parent does.
Chains are single-inheritance and acyclic — a cycle raises loudly the
moment the chain is resolved (`:schema`, `:validate`, `:defaults`,
`:chain` all resolve the chain). Editing a parent's schema does not
re-warn its child contracts at edit time; validation stays loud where
the chain is used — `:schema` / `:validate` calls and the publish gate.

## Ref surface (`AssetRef<dataType>`)

- `ref:schema()` — the merged field map (own fields + every field
  inherited through `extends`).
- `ref:validate(values)` — `(ok, violations)` against the merged
  schema. `violations` is an array of `{ path, message }`.
- `ref:defaults()` — the default value table the merged schema
  declares (a fresh, mutable table).
- `ref:parent()` — the parent contract ref (`extends`), or nil for a
  root contract.
- `ref:chain()` — the full extends chain as refs, root parent first,
  this contract last.
- `ref:instances()` — every `.data` instance bound to this contract or
  to a contract that extends it, as `AssetRef`s. A full scan over the
  world's data assets — a discovery surface for authoring and tooling,
  not a per-frame call.

## Discovery

- `asset.list("dataType")` — every registered contract, as `AssetRef`s.
- `asset.inspect("<name>")` — the contract's files, declared schema
  body, instance README, and this type README.
- `cat /zero/source/<Name>.dataType` — same summary.

## Authoring conventions

- Name contracts for the concept they type (`weapon`, `questObjective`,
  `lootTable`), not for a specific instance.
- Factor genuinely shared fields into a parent contract via `extends`;
  don't duplicate a field declaration across sibling contracts.
- Document every field's meaning and units in `README.md` — the schema
  only carries types and constraints, not intent.

## Common pitfalls

- **Redeclaring an inherited field.** `extends` merges parent fields
  in; a child that re-declares a field name the parent already
  declared is a merge error, not a silent override.
- **Cyclic `extends`.** Contract A extending B extending A raises
  loudly the first time the chain is resolved — fix the chain, there
  is no partial result to fall back to.
- **assetRef/dataRef without existence checks.** `assetType` and
  `contract` on ref fields are declaration-time requirements; the
  referenced asset or data instance is checked at validation time, not
  declaration time.

## Related types

- `.data` — a configured value instance bound to a dataType contract.
- `.preset` — a snapshot of one component's properties, not a typed
  multi-field contract.
- `.component` — executable entity behavior, versus this type's typed
  configuration data.
