DXNS, the schema language of DXN, on one page. The whole story is the reference; a gentle start is the tutorial.

A schema document

A .dxns file is a DXN map from names to definitions:

%{
  # A struct schema: a record that travels under its name, versioned.
  User: %schema(2){
    name: :string
    email: {:refine :string %{format: :email}}
    nickname?: :string                        # "?" makes a field optional
    role: %field{type: {:enum :admin :staff}, default: :staff, description: "What they may do"}
  }

  # A named type: a name for a type, used like any other.
  PositiveInt: {:refine :integer %{min: 1}}

  # A shape: a plain map with these fields, defaults filled in.
  Point: %shape{x: :float, y: :float, label: %field{type: :string, default: ""}}
}

Primitive types

TypeMatches
:anyany value
:neverno value
:nil, :booleannil; true or false
:integer, :float, :decimal, :rational42; 1.5; 19.99M; 22/7
:string, :char, :symbol, :keyword"text"; ?c; name; :name
:bytes, :bits@bytes "..."; whole bytes, or @bits {"..." n} too
:date, :time, :datetime, :local-datetime, :duration@date "2026-10-21", @time "...", @datetime "...Z", ...
:uuid, :objectid, :ip, :uri, :regex@uuid "...", @objectid "...", @ip "...", @uri "...", @regex "..."
:list, :tuple, :map, :ordered-map, :set, :sorted-set, :arraya collection of that kind, any elements
:timestampa datetime in UTC: {:refine :datetime %{offsets: ["Z"]}}
:int32, :int64, :uint32, :uint64an integer in that range
:float32a float that single precision holds exactly
:numberany integer, float, decimal or rational

Type forms

FormMatches
Namethe struct schema or named type Name (ns/Name in another file)
{:list-of T}a list, every element a T
{:list-items A {:repeat B 0 nil}}a list item by item: an A, then any number of B
{:repeat {:group A B} 1 3}inside list-items: A B together, once to three times
{:set-of T}, {:sorted-set-of T}, {:array-of T}that collection, every element a T
{:tuple-of A B C}a tuple of exactly these, in order
{:tuple-of-all T}a tuple of any length, every element a T
{:map-of K V}, {:ordered-map-of K V}every key a K, every value a V
{:enum a b c}exactly one of these literals
{:const v}exactly the value v
{:one-of A B}exactly one of A and B
{:any-of A B}one or more of them
{:all-of A B}all of them
{:not T}anything that is no T
{:nilable T}nil or a T
{:if I T E}an I must be a T; anything else an E (:any when left out)
{:refine T %{...}}a T that also meets the constraints below
{:case field %{v => T, :else => U}}the type the sibling field's value chooses
{:tagged acme.money T}the custom tag @acme.money around a T
{:doc T %{description: "..."}}a T, annotated (see below)
{:generic [t] body}a named type with parameters
{:of Name T}one use of a generic
%shape{...}a plain map with these fields
%schema(N){...}a struct schema, version N (1 when left out)

Refine constraints

KeyApplies toMeans
min, max, exclusive-min, exclusive-maxnumbers, dates, times, durationsa range, against a value of the same kind
multiple-ofnumbersan exact multiple
finitefloattrue: no NaN, no infinity
float32floattrue: single precision holds it
min-precision, max-precisiondecimaldigits of the coefficient, as written
min-exponent, max-exponentdecimalthe exponent (1.50M has -2)
bitsinteger, bytesonly these bit numbers may be set
min-length, max-lengthstring, keyword, symbol, bytes, bitscodepoints; bytes; bits under :bits
min-bytes, max-bytesstring, keyword, symbolUTF-8 bytes
patternstring, keyword, symbol, bytesmatches @regex "..."
formatstringone of the formats below
encodingstring:base64, :base64url, :base32, :base16
media-typestring"type/subtype", telling content how to read
contentstringholds a DXN document of the given type
encodes, encodes-seqbytesone .dxnb document, or several, of the given type
min-count, max-countlist, set, tuple, sorted set, arrayhow many elements
contains, min-contains, max-containsthose collectionshow many elements are a given type
unique, unique-bythose collectionsno two elements, or their field, the same
offsetsdatetime["Z" "+01:00"]: the allowed offsets
resolutiontime, datetime, local datetime, duration:second, :millisecond, :microsecond, :nanosecond
before-now, after-now, withindatetimeagainst the clock: within: @duration "PT1H"
version, prefixip4 or 6; true a prefix, false an address

An unknown key, or an argument of the wrong kind, is a compile error. A constraint refuses a value it does not apply to.

Formats

date, time, datetime, local-datetime, duration, uuid, ipv4, ipv6, hostname, idn-hostname, email, idn-email, uri, uri-reference, iri, iri-reference, uri-template, json-pointer, relative-json-pointer, semver, mac, host-port.

Annotations

KeyTakesMeans
title, descriptionstringa name; what it is for
exampleslistvalues the type takes
read-only, write-onlybooleanwritten by its owner only; never read back
deprecatedboolean or stringon its way out, with the reason
metamapanything else, kept as written
valuesmapon an enum: each value's own annotations

Fields

WrittenMeans
name: Trequired
name?: Toptional: may be absent
name: %field{type: T, default: v}absent means v
name: %field{type: T, description: "..."}documented
name: {:nilable T}present, but may be nil

Versions

WrittenMeans
%schema{...}version 1
%schema(3){...}version 3; every loaded version is kept
%User(3){...}data written against version 3
%User{...}data read as the latest loaded version

Append fields only; anything else deploys readers first, each with a materializer for the old version.

Files

FileNames its entries
acme.shop.dxnsacme.shop/Entry (a namespace file)
acme/shop/Order.dxnsacme.shop/Order, and acme.shop.Order/Line for another entry in it
acme/shop/Order/v2.dxns, Order-v2.dxnsversion 2 of acme.shop/Order

A bare Name means an entry of the same file; ns/Name an entry of another.

Errors

CategoryMeans
schema/compilethe schema is wrong
schema/type-mismatcha value is not of its type
schema/missing-fielda required field is absent
schema/undeclared-fielda strict decode met a field no schema declares
schema/unknown-versiondata was written against a version not loaded
schema/no-materializeran older version with nothing to upgrade it
schema/duplicate-versiontwo documents claim the same version
schema/not-loadedreplacing a version that was never loaded
schema/field-counta positional struct with the wrong number of items
schema/shadowed-fieldan extra field named like a declared one
schema/materializera materializer refused, or built a value its schema refuses
schema/version-disciplinea released version changed (the compatibility check)