Document Tree File Formats
This document provides complete specifications for all file formats used in VFS (Virtual File System) mode, where Morphir IR distributions are stored as a directory tree with individual files for each definition.
Serialization profile
A document tree maps logical manifest, module, NAME.type, and NAME.value documents to one homogeneous physical serialization profile:
| Logical document | JSON profile | YAML profile |
|---|---|---|
manifest | manifest.json | manifest.yaml |
module | module.json | module.yaml |
NAME.type | NAME.type.json | NAME.type.yaml |
NAME.value | NAME.value.json | NAME.value.yaml |
The extension is not part of a logical identity. A generated tree MUST use one profile for every file. If discovery finds both manifest.json and manifest.yaml, it MUST report ambiguity and MUST NOT select one implicitly. The structures documented below apply to both profiles; JSON examples use the JSON profile, and their YAML equivalents use the YAML profile.
Overview
In VFS mode, a Morphir IR distribution is organized as:
.morphir-dist/
├── manifest.yaml # Distribution metadata
└── pkg/
└── package-name/
└── module-path/
├── module.yaml # Module manifest
├── type-name.type.yaml # Type definitions
└── value-name.value.yaml # Value definitions
The corresponding JSON tree replaces each .yaml extension with .json.
File Types
1. Distribution Manifest (manifest.json)
Location: .morphir-dist/manifest.json
Purpose: Distribution-level metadata and configuration
Required Fields:
formatVersion: IR format versiondistribution: Distribution type ("Library","Specs", or"Application")package: Package name (canonical path format, e.g.,"my-org/my-project")
Optional Fields:
version: Package version (semantic version string)created: Creation timestamp (ISO 8601 format)layout: Distribution layout ("VfsMode"or"Classic", defaults to"VfsMode")entryPoints: Entry points map (required for Application distributions)
Schema: See morphir-ir-v4-document-tree-files.yaml → DistributionManifestFile
Example (Library):
{
"formatVersion": 4,
"distribution": "Library",
"package": "my-org/my-project",
"version": "1.2.0",
"created": "2026-01-15T12:00:00Z",
"layout": "VfsMode"
}
Example (Specs):
{
"formatVersion": 4,
"distribution": "Specs",
"package": "morphir/SDK",
"version": "3.0.0",
"created": "2026-01-15T12:00:00Z",
"layout": "VfsMode"
}
Example (Application):
{
"formatVersion": 4,
"distribution": "Application",
"package": "my-org/my-cli",
"version": "2.0.0",
"created": "2026-01-15T12:00:00Z",
"layout": "VfsMode",
"entryPoints": {
"startup": {
"target": "my-org/my-cli:main#run",
"kind": "main",
"doc": "Primary application entry point"
},
"build": {
"target": "my-org/my-cli:commands#build",
"kind": "command",
"doc": "Build the project"
}
}
}
2. Module Manifest (module.json)
Location: .morphir-dist/pkg/package-name/module-path/module.json
Purpose: Module metadata and optional inline definitions
Required Fields:
formatVersion: IR format versionpathormodule: Module path (canonical format, e.g.,"my-org/domain")
Note on
pathvsmodulefields:Both
pathandmodulefields are equivalent and accepted for backwards compatibility. Thepathfield is preferred for new files. When readingmodule.jsonfiles, tools should accept either field name.
Optional Fields:
doc: Module-level documentation (string or array of strings)types: Either array of type names (manifest style) or object with inline definitions (inline style)values: Either array of value names (manifest style) or object with inline definitions (inline style)
Encoding Styles:
Manifest Style (Granular)
Lists type/value names; definitions in separate files:
{
"formatVersion": 4,
"path": "my-org/domain",
"doc": "Domain model for main application",
"types": ["user", "user-ID", "order"],
"values": ["get-user-by-email", "create-order", "validate-user"]
}
Example with legacy module field (equivalent to path):
{
"formatVersion": 4,
"module": "my-org/domain",
"doc": "Domain model for main application",
"types": ["user", "order"],
"values": ["create-order"]
}
Inline Style (Hybrid)
Contains definitions directly:
{
"formatVersion": 4,
"path": "my-org/domain",
"doc": "Domain model for main application",
"types": {
"user": {
"access": "Public",
"doc": "Represents a user",
"TypeAliasDefinition": {
"typeParams": [],
"typeExp": {
"Record": {
"fields": {
"email": "morphir/SDK:string#string"
}
}
}
}
}
},
"values": {
"create-user": {
"access": "Public",
"ExpressionBody": {
"inputTypes": {},
"outputType": "my-org/domain:types#user",
"body": { "Literal": { "attributes": {}, "literal": { "StringLiteral": "..." } } }
}
}
}
}
Schema: See morphir-ir-v4-document-tree-files.yaml → ModuleManifestFile
3. Type Definition File (*.type.json)
Location: .morphir-dist/pkg/package-name/module-path/type-name.type.json
Purpose: Individual type definition or specification
Required Fields:
formatVersion: IR format versionname: Type name (canonical format, must match filename without.type.jsonsuffix)- Exactly one of:
def: Type definition (implementation) - containsTypeAliasDefinition,CustomTypeDefinition, orIncompleteTypeDefinitionspec: Type specification (interface) - containsTypeAliasSpecification,OpaqueTypeSpecification,CustomTypeSpecification, orDerivedTypeSpecification
Optional Fields:
doc: Documentation (string or array of strings) - can be at top level or nested indef/spec
File Naming:
- Use the escaped stem,
escape(name), not the canonical name - Suffix:
.type.json - Example:
user.type.json,user-_id.type.json,order-line-item.type.json
Schema: See morphir-ir-v4-document-tree-files.yaml → TypeDefinitionFile
Example (Definition):
{
"formatVersion": 4,
"name": "user",
"doc": "Represents a user in the system",
"def": {
"access": "Public",
"TypeAliasDefinition": {
"typeParams": [],
"typeExp": {
"Record": {
"fields": {
"user-id": "my-org/domain:types#user-ID",
"email": "morphir/SDK:string#string",
"created-at": "my-org/SDK:local-date-time#local-date-time"
}
}
}
}
}
}
Note on Design Document Examples:
Some examples in the design documents (
docs/design/draft/ir/distributions.md) may be simplified and omit theaccessfield for brevity. In actual VFS files that are part of a PackageDefinition, theaccessfield is required indefobjects. The examples in this specification document show the complete, valid format.
Example (Specification):
{
"formatVersion": 4,
"name": "int",
"spec": {
"doc": "Arbitrary precision integer",
"OpaqueTypeSpecification": {}
}
}
Example (Custom Type Definition):
{
"formatVersion": 4,
"name": "order-status",
"def": {
"access": "Public",
"CustomTypeDefinition": {
"typeParams": [],
"access": "Public",
"value": {
"constructors": {
"pending": [],
"processing": [],
"shipped": [],
"delivered": [],
"cancelled": []
}
}
}
}
}
4. Value Definition File (*.value.json)
Location: .morphir-dist/pkg/package-name/module-path/value-name.value.json
Purpose: Individual value definition or specification
Required Fields:
formatVersion: IR format versionname: Value name (canonical format, must match filename without.value.jsonsuffix)- Exactly one of:
def: Value definition (implementation) - contains wrapper object withExpressionBody,NativeBody,ExternalBody, orIncompleteBodyspec: Value specification (interface) - containsinputs(object) andoutput(type)
Optional Fields:
doc: Documentation (string or array of strings) - can be at top level or nested indef/spec
File Naming:
- Use the escaped stem,
escape(name), not the canonical name - Suffix:
.value.json - Example:
get-user-by-email.value.json,create-order.value.json,validate-email.value.json
Schema: See morphir-ir-v4-document-tree-files.yaml → ValueDefinitionFile
Example (Definition with ExpressionBody):
{
"formatVersion": 4,
"name": "get-user-by-email",
"doc": "Retrieve a user by email address",
"def": {
"access": "Public",
"ExpressionBody": {
"inputTypes": {
"email": "morphir/SDK:string#string",
"users": ["morphir/SDK:list#list", "my-org/domain:types#user"]
},
"outputType": ["morphir/SDK:maybe#maybe", "my-org/domain:types#user"],
"body": {
"Apply": {
"attributes": {},
"function": {
"Reference": {
"attributes": {},
"fqname": "morphir/SDK:list#find",
"args": []
}
},
"argument": {
"Variable": {
"attributes": {},
"name": "email"
}
}
}
}
}
}
}
Note on Type Reference Formats:
Type references in
inputTypes,outputType, andtypeExpfields can use either:
- Canonical string format:
"morphir/SDK:string#string"(preferred, more compact)- Array format:
["morphir/SDK:list#list", "my-org/domain:types#user"](for parameterized types)Both formats are valid. The canonical string format is preferred for simple types, while array format is used for parameterized types where the first element is the type constructor and subsequent elements are type arguments.
Example (Definition with NativeBody):
{
"formatVersion": 4,
"name": "add",
"def": {
"access": "Public",
"NativeBody": {
"inputTypes": {
"a": "morphir/SDK:basics#int",
"b": "morphir/SDK:basics#int"
},
"outputType": "morphir/SDK:basics#int",
"nativeInfo": {
"hint": { "Arithmetic": {} }
}
}
}
}
Example (Specification):
{
"formatVersion": 4,
"name": "validate-email",
"spec": {
"doc": [
"Validate an email address format.",
"Returns true if the email is valid, false otherwise."
],
"inputs": {
"email": "morphir/SDK:string#string"
},
"output": "morphir/SDK:basics#bool"
}
}
Directory Structure
Standard Layout
.morphir-dist/
├── manifest.json # Distribution metadata
└── pkg/
└── my-org/
└── my-project/ # Package directory
├── domain/ # Module directory
│ ├── module.json # Module manifest
│ ├── user.type.json # Type definition
│ ├── user-_id.type.json # Type definition
│ ├── order.type.json # Type definition
│ ├── get-user.value.json # Value definition
│ └── create-order.value.json
└── api/ # Another module
├── module.json
├── request.type.json
└── handle-request.value.json
Nested Modules
Modules can be nested by creating subdirectories:
.morphir-dist/
└── pkg/
└── my-org/
└── my-project/
└── domain/
├── module.json # domain module
├── user.type.json
└── orders/ # domain/orders submodule
├── module.json # domain/orders module
├── order.type.json
└── shipping/ # domain/orders/shipping submodule
├── module.json # domain/orders/shipping module
└── address.type.json
Field Details
formatVersion
formatVersion follows the shared v3-and-later contract.
Type: Integer 4 or an exact v4 release string
Required: Yes
Description: Integer 4 is the canonical v4.0.0 baseline. Exact strings such as
"4.1.0" identify later v4 revisions. The noncanonical baseline string "4.0.0"
is also accepted. Prerelease and build metadata are rejected.
Canonical baseline:
"formatVersion": 4
Accepted exact later revision:
"formatVersion": "4.1.0"
name
Type: Name (canonical string format)
Required: Yes (in *.type.json and *.value.json files)
Description: The canonical name of the type or value
Format: Segments joined by -, where a segment is all-lowercase (a word) or all-uppercase (an initialism)
"user""get-user-by-email""value-in-USD""user-ID"
Constraint: escape(name) must equal the filename without its suffix. The name itself is not the filename:
user-ID is stored in user-_id.type.json. See Naming for the escape and for the
fileNames map that a module carries when a stem is truncated for path length.
path / module
Type: ModuleName (canonical path format)
Required: Yes (in module.json, either field)
Description: Module path
Format: Forward-slash separated segments
"domain""my-org/domain""domain/orders/shipping"
Note: path and module are equivalent; path is preferred for new files, while module is accepted for backwards compatibility with legacy files.
doc
Type: String or Array of Strings
Required: No
Description: Documentation
Formats:
- Single-line:
"doc": "Brief description" - Multi-line:
"doc": ["Line 1", "Line 2", "Line 3"]
Location: Can appear at:
- Top level of file
- Nested in
deforspecobject - Both (top-level takes precedence for display)
def
Type: Object
Required: Yes (if this is a definition file)
Description: Type or value definition (implementation)
For Type Definitions:
- Must contain exactly one of:
TypeAliasDefinition,CustomTypeDefinition,IncompleteTypeDefinition - Must include
accessfield ("Public"or"Private") when part of PackageDefinition - May include
docfield
For Value Definitions:
- Must contain wrapper object with exactly one of:
ExpressionBody,NativeBody,ExternalBody,IncompleteBody - Must include
accessfield ("Public"or"Private") when part of PackageDefinition - May include
docfield
Example (Type):
{
"def": {
"access": "Public",
"doc": "User type",
"TypeAliasDefinition": {
"typeParams": [],
"typeExp": "morphir/SDK:string#string"
}
}
}
Example (Value):
{
"def": {
"access": "Public",
"doc": "Create a user",
"ExpressionBody": {
"inputTypes": {},
"outputType": "my-org/domain:types#user",
"body": { "Literal": { "attributes": {}, "literal": { "StringLiteral": "..." } } }
}
}
}
spec
Type: Object
Required: Yes (if this is a specification file)
Description: Type or value specification (interface)
For Type Specifications:
- Must contain exactly one of:
TypeAliasSpecification,OpaqueTypeSpecification,CustomTypeSpecification,DerivedTypeSpecification - May include
docfield
For Value Specifications:
- Must contain:
inputs: Object mapping parameter names to typesoutput: Type
- May include
docfield
Example (Type):
{
"spec": {
"doc": "Integer type",
"OpaqueTypeSpecification": {}
}
}
Example (Value):
{
"spec": {
"doc": "Add two integers",
"inputs": {
"a": "morphir/SDK:basics#int",
"b": "morphir/SDK:basics#int"
},
"output": "morphir/SDK:basics#int"
}
}
Access Control
In PackageDefinition Context
When type/value files are part of a PackageDefinition:
defobjects must includeaccessfield- Values:
"Public"or"Private" - Determines visibility within the package
In PackageSpecification Context
When type/value files are part of a PackageSpecification:
- Only public items are included
specobjects do not includeaccessfield (specs are always public)
Advanced Examples
Incomplete Type Definition
user.type.json (with incomplete definition):
{
"formatVersion": 4,
"name": "user",
"def": {
"access": "Public",
"IncompleteTypeDefinition": {
"typeParams": [],
"reason": {
"UnresolvedReference": {
"target": "my-org/domain:types#missing-type"
}
}
}
}
}
External Value Definition
external-api.value.json:
{
"formatVersion": 4,
"name": "call-external-api",
"def": {
"access": "Public",
"ExternalBody": {
"inputTypes": {
"url": "morphir/SDK:string#string",
"payload": "morphir/SDK:json#json"
},
"outputType": ["morphir/SDK:result#result", "morphir/SDK:json#json", "morphir/SDK:string#string"],
"externalInfo": {
"provider": "http",
"endpoint": "/api/v1/data",
"method": "POST"
}
}
}
}
Value with Complex Expression Body
calculate-total.value.json:
{
"formatVersion": 4,
"name": "calculate-total",
"doc": [
"Calculate the total price of an order including tax.",
"Applies discounts and regional tax rates."
],
"def": {
"access": "Public",
"ExpressionBody": {
"inputTypes": {
"order": "my-org/domain:orders#order",
"tax-rate": "morphir/SDK:basics#float"
},
"outputType": "morphir/SDK:basics#float",
"body": {
"LetDefinition": {
"attributes": {},
"valueName": "subtotal",
"valueDefinition": {
"ExpressionBody": {
"inputTypes": {},
"outputType": "morphir/SDK:basics#float",
"body": {
"Apply": {
"attributes": {},
"function": {
"Reference": {
"attributes": {},
"fqname": "morphir/SDK:list#sum",
"args": []
}
},
"argument": {
"Field": {
"attributes": {},
"subject": {
"Variable": {
"attributes": {},
"name": "order"
}
},
"fieldName": "line-items"
}
}
}
}
}
},
"inValue": {
"Apply": {
"attributes": {},
"function": {
"Reference": {
"attributes": {},
"fqname": "morphir/SDK:basics#multiply",
"args": []
}
},
"argument": {
"Tuple": {
"attributes": {},
"elements": [
{
"Variable": {
"attributes": {},
"name": "subtotal"
}
},
{
"Apply": {
"attributes": {},
"function": {
"Reference": {
"attributes": {},
"fqname": "morphir/SDK:basics#add",
"args": []
}
},
"argument": {
"Tuple": {
"attributes": {},
"elements": [
{
"Literal": {
"attributes": {},
"literal": { "FloatLiteral": 1.0 }
}
},
{
"Variable": {
"attributes": {},
"name": "tax-rate"
}
}
]
}
}
}
}
]
}
}
}
}
}
}
}
}
}
Type with Type Parameters
result.type.json:
{
"formatVersion": 4,
"name": "result",
"spec": {
"doc": "Result type representing success or error",
"CustomTypeSpecification": {
"typeParams": ["ok", "err"],
"value": {
"constructors": {
"ok": [["value", "ok"]],
"err": [["error", "err"]]
}
}
}
}
}
Module with Mixed Styles
module.json (manifest style with some inline definitions):
{
"formatVersion": 4,
"path": "my-org/domain",
"doc": "Domain model",
"types": ["user", "order"],
"values": {
"create-user": {
"access": "Public",
"ExpressionBody": {
"inputTypes": {
"email": "morphir/SDK:string#string"
},
"outputType": "my-org/domain:types#user",
"body": {
"Constructor": {
"attributes": {},
"fqname": "my-org/domain:types#user",
"args": [
{
"Variable": {
"attributes": {},
"name": "email"
}
}
]
}
}
}
}
}
}
Note: While mixing styles is technically possible, it's recommended to use consistent style per module for clarity.
Complete Examples
Complete Module Structure
Directory: .morphir-dist/pkg/my-org/my-project/domain/
module.json:
{
"formatVersion": 4,
"path": "my-org/domain",
"doc": "Domain model for the application",
"types": ["user", "user-ID", "order"],
"values": ["get-user-by-email", "create-order", "validate-user"]
}
user.type.json:
{
"formatVersion": 4,
"name": "user",
"doc": "Represents a user in the system",
"def": {
"access": "Public",
"TypeAliasDefinition": {
"typeParams": [],
"typeExp": {
"Record": {
"fields": {
"user-id": "my-org/domain:types#user-ID",
"email": "morphir/SDK:string#string",
"created-at": "my-org/SDK:local-date-time#local-date-time"
}
}
}
}
}
}
user-_id.type.json:
{
"formatVersion": 4,
"name": "user-ID",
"def": {
"access": "Public",
"CustomTypeDefinition": {
"typeParams": [],
"access": "Public",
"value": {
"constructors": {
"user-ID": [
["id", "morphir/SDK:string#string"]
]
}
}
}
}
}
get-user-by-email.value.json:
{
"formatVersion": 4,
"name": "get-user-by-email",
"doc": "Retrieve a user by their email address",
"def": {
"access": "Public",
"ExpressionBody": {
"inputTypes": {
"email": "morphir/SDK:string#string",
"users": ["morphir/SDK:list#list", "my-org/domain:types#user"]
},
"outputType": ["morphir/SDK:maybe#maybe", "my-org/domain:types#user"],
"body": {
"Apply": {
"attributes": {},
"function": {
"Reference": {
"attributes": {},
"fqname": "morphir/SDK:list#find",
"args": []
}
},
"argument": {
"Variable": {
"attributes": {},
"name": "email"
}
}
}
}
}
}
}
Validation Rules
File Naming
A filename is the escaped stem of a Name, not the canonical name. See Naming for the escape.
- ✅ Must be
escape(name), matching^_?[a-z0-9]+(-_?[a-z0-9]+)*(__[0-9a-f]{8})?_?$ - ✅ Type files:
*.type.json - ✅ Value files:
*.value.json - ✅ Module files:
module.json(exact name) - ✅ Manifest file:
manifest.json(exact name, at root) - ❌ No spaces, periods, or characters outside
[a-z0-9_-] - ❌ No uppercase letters. Case carries meaning in a canonical name but not in a filename, because a
case-insensitive filesystem cannot keep
value-in-USDandvalue-in-usdapart. The escape encodes an initialism as a_prefix instead.
Valid Examples:
user.type.json✅ (nameuser)user-_id.type.json✅ (nameuser-ID)get-user-by-email.value.json✅value-in-_usd.value.json✅ (namevalue-in-USD)aux_.type.json✅ (nameaux, suffixed because Windows reserves the device name)_con.type.json✅ (nameCON)
Invalid Examples:
User.type.json❌ (uppercase; the escaped stem is always lowercase)user-ID.type.json❌ (canonical name used verbatim; escape it touser-_id)user-(id).type.json❌ (the retired parenthesized encoding)user id.type.json❌ (space)user.id.type.json❌ (period, use hyphen)aux.type.json❌ (Windows reserved device name; escape it toaux_)
Required Fields
- All files:
formatVersion - Definition files:
name, exactly one ofdeforspec - Module files:
pathormodule - Manifest files:
distribution,package
Field Consistency
namefield must match filename (without suffix)path/modulefield must match directory structuredefandspecare mutually exclusive (exactly one required)
Example: If file is user.type.json, then name must be "user".
Example: If file is in .morphir-dist/pkg/my-org/my-project/domain/, then path should be "my-org/domain" or "my-org/my-project/domain" depending on package structure.
Type and Value Definition Validation
Type Definitions (def in *.type.json):
- Must contain exactly one of:
TypeAliasDefinition,CustomTypeDefinition,IncompleteTypeDefinition - Must include
accessfield when part of PackageDefinition TypeAliasDefinitionmust havetypeParams(array) andtypeExp(type)CustomTypeDefinitionmust havetypeParams,access, andvalue.constructors(object)IncompleteTypeDefinitionmust havetypeParamsandreason(HoleReason)
Type Specifications (spec in *.type.json):
- Must contain exactly one of:
TypeAliasSpecification,OpaqueTypeSpecification,CustomTypeSpecification,DerivedTypeSpecification OpaqueTypeSpecificationmust be empty object{}TypeAliasSpecificationmust havetypeParamsandtypeExpCustomTypeSpecificationmust havetypeParamsandvalue.constructors
Value Definitions (def in *.value.json):
- Must contain wrapper object with exactly one of:
ExpressionBody,NativeBody,ExternalBody,IncompleteBody - Must include
accessfield when part of PackageDefinition ExpressionBodymust haveinputTypes(object),outputType(type), andbody(expression)NativeBodymust haveinputTypes,outputType, andnativeInfoExternalBodymust haveinputTypes,outputType, andexternalInfoIncompleteBodymust haveinputTypes,outputType, andreason
Value Specifications (spec in *.value.json):
- Must have
inputs(object mapping parameter names to types) - Must have
output(type) - May have
doc(string or array of strings)
Module Manifest Validation
Manifest Style:
typesmust be array of Name stringsvaluesmust be array of Name strings- Referenced type/value files must exist in same directory
Inline Style:
typesmust be object mapping names to AccessControlled TypeDefinitionvaluesmust be object mapping names to AccessControlled ValueDefinition- Each definition must include
accessfield
Hybrid Style (not recommended but allowed):
- One of
types/valuescan be array, other can be object - Consistency is preferred
Distribution Manifest Validation
Required for all distributions:
formatVersion: Must satisfy the shared v3-and-later contractdistribution: Must be"Library","Specs", or"Application"package: Must be valid PackageName (canonical format)
Required for Application distributions:
entryPoints: Must be present and non-empty object- Each entry point must have
target(FQName) andkind(EntryPointKind)
Optional but recommended:
version: Semantic version stringcreated: ISO 8601 timestamplayout: Should be"VfsMode"for document tree distributions
Directory Structure Validation
Package Directory:
- Must match
packagefield inmanifest.json - Path:
.morphir-dist/pkg/{package-path}/
Module Directory:
- Must match
path/modulefield inmodule.json - Path:
.morphir-dist/pkg/{package-path}/{module-path}/ - Must contain
module.jsonfile
Definition Files:
- Must be in module directory
- Filename must match
namefield in file - Type files:
{name}.type.json - Value files:
{name}.value.json
Error Handling
Common Validation Errors
Missing Required Field:
// ❌ Missing 'name' field
{
"formatVersion": 4,
"def": { ... }
}
Name Mismatch:
// ❌ File is 'user.type.json' but name is 'order'
{
"formatVersion": 4,
"name": "order",
"def": { ... }
}
Both def and spec Present:
// ❌ Cannot have both def and spec
{
"formatVersion": 4,
"name": "user",
"def": { ... },
"spec": { ... }
}
Missing Access Field:
// ❌ Missing 'access' in def (required for PackageDefinition)
{
"formatVersion": 4,
"name": "user",
"def": {
"TypeAliasDefinition": { ... }
}
}
Invalid Entry Points:
// ❌ Application distribution missing entryPoints
{
"formatVersion": 4,
"distribution": "Application",
"package": "my-org/my-cli"
// Missing entryPoints!
}
Recommended Error Messages
When validation fails, provide clear error messages:
- File naming:
"Filename 'User.type.json' does not match canonical name format. Expected 'user.type.json'" - Name mismatch:
"Name field 'order' does not match filename 'user.type.json'" - Missing field:
"Required field 'name' is missing in type definition file" - Both def/spec:
"Cannot have both 'def' and 'spec' fields. Use exactly one." - Missing access:
"Definition in PackageDefinition context must include 'access' field" - Invalid entry points:
"Application distribution must include 'entryPoints' field"
Schema Reference
Formal JSON schemas are available in:
- morphir-ir-v4-document-tree-files.yaml - Complete schemas for all file formats
- morphir-ir-v4.yaml - Core IR schema (referenced by document tree files)
Metadata Files
Package Metadata
Package-level metadata can be stored in additional files:
Location: .morphir-dist/pkg/package-name/package.json (optional)
Purpose: Package-level metadata, dependencies, configuration
Example:
{
"formatVersion": 4,
"package": "my-org/my-project",
"version": "1.2.0",
"description": "My project description",
"dependencies": {
"morphir/SDK": "3.0.0"
},
"metadata": {
"author": "My Org",
"license": "Apache-2.0",
"repository": "https://github.com/my-org/my-project"
}
}
Note: Package metadata files (package.json) are optional and not part of the core V4 IR schema. They are documented here for reference, but implementations are not required to support them. The manifest.json file contains all essential distribution metadata required by the V4 specification. Package metadata files may be used by tooling for additional metadata, but are not validated by the core IR schema.
Module Metadata
Module-level metadata is stored in module.json. Additional metadata can be included:
Example with extended metadata:
{
"formatVersion": 4,
"path": "my-org/domain",
"doc": "Domain model",
"types": ["user", "order"],
"values": ["create-order"],
"metadata": {
"tags": ["domain", "core"],
"deprecated": false,
"since": "1.0.0"
}
}
Metadata Fields (all optional):
tags: Array of string tags for categorizationdeprecated: Boolean indicating if module is deprecatedsince: Version when module was introducedextensions: Object for tool-specific metadata
File Format Comparison
Classic Mode vs VFS Mode
| Aspect | Classic Mode | VFS Mode |
|---|---|---|
| Structure | Single morphir-ir.json file | Directory tree with individual files |
| Manifest File | Not separate (embedded in root) | .morphir-dist/manifest.json |
| Module Structure | Nested in distribution JSON | module.json file per module |
| Type Definitions | Nested in module JSON | *.type.json files |
| Value Definitions | Nested in module JSON | *.value.json files |
| Use Case | Simple projects, backwards compat | Large projects, incremental updates |
Complete Directory Tree Example
.morphir-dist/
├── manifest.json
└── pkg/
└── my-org/
└── my-project/
├── domain/
│ ├── module.json
│ ├── user.type.json
│ ├── user-_id.type.json
│ ├── order.type.json
│ ├── get-user-by-email.value.json
│ └── create-order.value.json
├── api/
│ ├── module.json
│ ├── request.type.json
│ ├── response.type.json
│ └── handle-request.value.json
└── utils/
├── module.json
├── validation.type.json
└── validate-email.value.json
Related Documentation
- Module Structure - Module concepts and structure
- Distribution Structure - Distribution modes and VFS examples
- V4 Schema - Complete V4 schema documentation
- V4 Schema YAML - Formal JSON schema