Skip to main content

morphir.toml Specification

This document provides the complete specification for the morphir.toml configuration file format.

File Format​

Morphir uses TOML v1.0.0 for configuration files. All configuration is in morphir.toml at the project or workspace root.

Top-Level Sections​

SectionRequiredDescription
[morphir]NoMorphir toolchain settings
[project]ConditionalProject metadata (required for project mode)
[workspace]ConditionalWorkspace settings (required for workspace mode)
[frontend]NoSource language configuration
[ir]NoIR format and generation settings
[codegen]NoCode generation targets and options
[dependencies]NoProject dependencies
[dev-dependencies]NoDevelopment-only dependencies
[extensions]NoExtension registration
[tasks]NoCustom tasks and hooks
[test]NoTest configuration
[publish]NoPublishing configuration

[morphir] Section​

Morphir toolchain version and global settings.

[morphir]
# Required Morphir IR version (semver constraint)
# Ensures compatibility with toolchain and extensions
version = "^4.0.0"

# Minimum CLI version required (optional)
min_cli_version = "4.0.0"

Fields​

FieldTypeDefaultDescription
versionstringRequiredSemver constraint for IR version (e.g., "^4.0.0", "~4.1", "4.0.0")
min_cli_versionstringNoneMinimum CLI version required

Version Constraint Syntax​

SyntaxMeaningExample
"4.0.0"Exact versionOnly 4.0.0
"^4.0.0"Compatible (major)>=4.0.0, <5.0.0
"~4.1.0"Compatible (minor)>=4.1.0, <4.2.0
">=4.0.0"Minimum version4.0.0 or higher
">=4.0.0, <5.0.0"RangeBetween 4.0.0 and 5.0.0

[project] Section​

Project metadata and structure. Required for project mode.

[project]
# Package identifier (organization/name format)
name = "my-org/my-project"

# Semantic version
version = "1.0.0"

# Human-readable description
description = "A Morphir domain model for order processing"

# Package authors
authors = ["Jane Doe <jane@example.com>"]

# License identifier (SPDX)
license = "Apache-2.0"

# Repository URL
repository = "https://github.com/my-org/my-project"

# Homepage URL
homepage = "https://my-org.github.io/my-project"

# Source directory (relative to morphir.toml)
source_directory = "src"

# Modules exposed as public API
exposed_modules = ["Domain.User", "Domain.Order", "Domain.Product"]

# Keywords for package discovery
keywords = ["domain", "orders", "e-commerce"]

Fields​

FieldTypeDefaultDescription
namestringRequiredPackage identifier in org/name format
versionstring"0.1.0"Semantic version (e.g., "1.0.0", "2.1.0-beta.1")
descriptionstring""Human-readable description
authorsarray[]List of authors (name and/or email)
licensestringNoneSPDX license identifier
repositorystringNoneRepository URL
homepagestringNoneHomepage URL
source_directorystring"src"Source code directory
exposed_modulesarrayAll modulesModules in the public API
keywordsarray[]Keywords for discovery

Package Name Format​

Package names follow the format organization/project-name:

  • Organization: Lowercase, alphanumeric, hyphens allowed (e.g., my-org, finos)
  • Project: Lowercase, alphanumeric, hyphens allowed (e.g., my-project, morphir-sdk)
  • Separator: Forward slash /

Examples:

  • morphir/sdk
  • my-company/order-domain
  • finos/morphir-examples

[workspace] Section​

Workspace configuration for multi-project setups.

[workspace]
# Glob patterns for discovering member projects
members = [
"packages/*",
"libs/*",
"apps/*"
]

# Patterns to exclude from member discovery
exclude = [
"packages/deprecated-*",
"packages/internal-*"
]

# Default member for commands without --project flag
default_member = "packages/core"

# Out directory for every task in the workspace
out_dir = ".morphir/out"

# Parallel build settings
parallel = true
max_jobs = 4

Fields​

FieldTypeDefaultDescription
membersarray[]Glob patterns for member discovery
excludearray[]Patterns to exclude from discovery
default_memberstringNoneDefault project for commands
out_dirstring".morphir/out"Out directory for every task in the workspace
parallelbooltrueEnable parallel builds
max_jobsintegerCPU countMaximum parallel jobs

Member Discovery​

Members are discovered by:

  1. Matching directories against members patterns
  2. Excluding matches against exclude patterns
  3. Finding morphir.toml with [project] section in matched directories

[frontend] Section​

Source language and parser configuration.

[frontend]
# Default source language
language = "elm"

# Language-specific settings
[frontend.elm]
extension = "morphir-elm-native"
elm_version = "0.19"
optimize = true

[frontend.morphir-dsl]
strict_mode = true
allow_incomplete = false

# Pattern-based language selection
[[frontend.rules]]
pattern = "src/legacy/**/*.morphir"
language = "morphir-dsl"

[[frontend.rules]]
pattern = "src/experimental/**/*.ml"
language = "ocaml"

Fields​

FieldTypeDefaultDescription
languagestringAuto-detectDefault source language

Built-in Languages​

LanguageExtensionsDescription
elm.elmElm source files
morphir-dsl.morphir, .mdslMorphir DSL

Language-Specific Options​

[frontend.elm]​

FieldTypeDefaultDescription
elm_versionstring"0.19"Elm language version
optimizeboolfalseEnable optimizations
preludestring or table"elm-core"Implicit imports and SDK module aliases every module is compiled against
extensionstringThe language's default providerExtension id of the frontend provider that compiles this language

extension is implemented today and is a per-language key: it is valid under any [frontend.<language>] table, because a provider belongs to a language and [[frontend.rules]] may send different paths to different languages. It names an extension id, such as "morphir-elm-native", and selects that provider the same way --extension does, including opt-in built-ins. --extension overrides it, and with neither the language's default provider applies. An id that does not provide the language fails the run. A value that is not a usable extension id — blank, of the wrong type, or malformed — is a configuration error naming frontend.<language>.extension, unless --extension is given. When it is, the flag's provider is used and the broken value is ignored, with a warning on stderr. Other configuration errors, such as an ambiguous [frontend.<language>] table from two spellings that differ only in case, still fail the run either way: only a malformed extension value is excused by the flag.

prelude is implemented today and read by the native morphir-elm-native provider, which receives it as the elmPrelude compile option; the JavaScript morphir-elm extension ignores it. It is either the name of a built-in prelude ("elm-core" or "none") or a [frontend.elm.prelude] table holding id, implicit_import, module_alias, and package. See Choosing the Elm prelude.

[frontend.morphir-dsl]​

FieldTypeDefaultDescription
strict_modeboolfalseStrict parsing mode
allow_incompletebooltrueAllow incomplete definitions

Frontend Rules​

Rules select language based on file path patterns:

[[frontend.rules]]
pattern = "src/**/*.elm" # Glob pattern
language = "elm" # Language for matching files

Rules are evaluated in order; first match wins.

[ir] Section​

IR format and generation settings.

[ir]
# IR format version
format_version = 4

# Storage layout compile writes
layout = "single-file" # "single-file" or "document-tree"

# Serialization format compile writes
format = "json" # "json" or "yaml"

# Strict mode (fail on warnings)
strict_mode = false

# Include source locations in IR
include_source_locations = true

# Preserve documentation
include_docs = true

Fields​

FieldTypeDefaultDescription
format_versioninteger4IR format version
layoutstring"single-file"Storage layout compile writes: "single-file" or "document-tree"
formatstring"json"Serialization format compile writes: "json" or "yaml"
modestringDeprecated alias for layout: "classic" means "single-file", "vfs" means "document-tree". Setting it prints a warning; an explicit layout wins
strict_modeboolfalseTreat warnings as errors
include_source_locationsbooltrueInclude source locations in IR
include_docsbooltrueInclude documentation in IR

[codegen] Section​

Code generation configuration.

[codegen]
# Targets to generate
targets = ["typescript", "scala", "spark"]

# Output format
output_format = "pretty" # "pretty" or "compact"

# Output directory (relative to project output)
output_dir = "generated"

# Target-specific configuration
[codegen.typescript]
module_format = "esm"
strict = true

[codegen.scala]
package_prefix = "com.myorg"
scala_version = "2.13"

[codegen.spark]
spark_version = "3.5"
scala_version = "2.13"

# Module-specific target overrides
[codegen.modules."Domain.Api"]
targets = ["typescript"] # Only generate TypeScript for this module

[codegen.modules."Domain.Internal"]
targets = [] # Skip codegen for internal modules

# Pattern-based rules
[[codegen.rules]]
pattern = "**/Internal/**"
targets = []

[[codegen.rules]]
pattern = "**/Api/**"
targets = ["typescript", "openapi"]

Fields​

FieldTypeDefaultDescription
targetsarray[]Code generation targets
output_formatstring"pretty"Output formatting
output_dirstring"generated"Output directory

Built-in Targets​

TargetDescription
typescriptTypeScript/JavaScript
scalaScala 2.x/3.x
javaJava
sparkApache Spark
json-schemaJSON Schema
openapiOpenAPI specification

Target-Specific Options​

[codegen.typescript]​

FieldTypeDefaultDescription
module_formatstring"esm""esm", "commonjs", or "umd"
strictbooltrueEnable strict TypeScript
declarationbooltrueGenerate .d.ts files

[codegen.scala]​

FieldTypeDefaultDescription
package_prefixstringNonePackage prefix
scala_versionstring"2.13"Scala version

[codegen.spark]​

FieldTypeDefaultDescription
spark_versionstring"3.5"Spark version
scala_versionstring"2.13"Scala version

[dependencies] Section​

Project dependencies.

[dependencies]
# Path dependency (local)
"my-org/common" = { path = "../common" }

# Version dependency (from registry)
"morphir/sdk" = "^3.0.0"

# Git dependency
"other-org/utils" = { git = "https://github.com/other-org/utils.git", tag = "v1.0.0" }

# Detailed specification
[dependencies."finos/morphir-examples"]
version = "^2.0.0"
features = ["extra-types"]

Dependency Formats​

Version String (Registry)​

"morphir/sdk" = "^3.0.0"

Path (Local)​

"my-org/common" = { path = "../common" }

Git​

# By tag
"org/pkg" = { git = "https://github.com/org/pkg.git", tag = "v1.0.0" }

# By branch
"org/pkg" = { git = "https://github.com/org/pkg.git", branch = "main" }

# By commit
"org/pkg" = { git = "https://github.com/org/pkg.git", rev = "abc123" }

Detailed​

[dependencies."org/pkg"]
version = "^2.0.0"
features = ["feature1", "feature2"]
optional = false

Dependency Fields​

FieldTypeDescription
versionstringSemver constraint
pathstringLocal path
gitstringGit repository URL
tagstringGit tag
branchstringGit branch
revstringGit commit hash
featuresarrayOptional features to enable
optionalboolOptional dependency

[dev-dependencies] Section​

Development-only dependencies (same format as [dependencies]).

[dev-dependencies]
"morphir/test-utils" = "^1.0.0"
"my-org/test-fixtures" = { path = "../test-fixtures" }

[extensions] Section​

Extension registration and configuration.

[extensions]
# WASM component (local path)
spark-codegen = { path = "./extensions/spark-codegen.wasm" }

# WASM component (URL)
scala-codegen = { url = "https://extensions.morphir.dev/scala-codegen-1.0.0.wasm" }

# Native executable
my-analyzer = { command = "./bin/my-analyzer", args = ["--mode", "jsonrpc"] }

# Disable auto-discovered extension
legacy-ext = { enabled = false }

# Extension-specific configuration
[extensions.spark-codegen.config]
spark_version = "3.5"
scala_version = "2.13"

Extension Fields​

FieldTypeDescription
pathstringLocal path to WASM or executable
urlstringURL to download extension
commandstringExecutable command
argsarrayCommand arguments
enabledboolEnable/disable extension
configtableExtension-specific configuration

[tasks] Section​

Custom tasks and hooks.

[tasks]
# Simple command task
lint = "elm-review"

# Task with description
[tasks.integration]
description = "Run integration tests"
run = "./scripts/integration-tests.sh"

# Task with dependencies
[tasks.ci]
description = "Full CI pipeline"
depends = ["check", "test", "build"]

# Task with working directory
[tasks.docs]
description = "Generate documentation"
run = "morphir docs generate"
cwd = "./docs"

# Pre/post hooks for built-in tasks
[tasks."pre:build"]
run = "echo 'Starting build...'"

[tasks."post:build"]
run = "prettier --write .morphir-dist/"

[tasks."post:codegen"]
run = "./scripts/post-codegen.sh"

Task Fields​

FieldTypeDescription
descriptionstringHuman-readable description
runstringShell command to execute
dependsarrayTask dependencies (run first)
cwdstringWorking directory
envtableEnvironment variables

Built-in Tasks​

TaskDescription
buildCompile project to IR
checkLint and validate
testRun tests
codegenGenerate code for targets
packCreate distributable package
publishPublish to registry
cleanRemove build artifacts

Hooks​

Hooks extend built-in tasks:

HookTiming
pre:<task>Before task runs
post:<task>After task succeeds

[test] Section​

Test configuration.

[test]
# Test directory
directory = "tests"

# Test patterns
include = ["**/*Test.elm", "**/*Spec.elm"]
exclude = ["**/helpers/**"]

# Test runner settings
timeout = 30000 # milliseconds
parallel = true

Fields​

FieldTypeDefaultDescription
directorystring"tests"Test directory
includearray["**/*Test.*"]Include patterns
excludearray[]Exclude patterns
timeoutinteger30000Test timeout (ms)
parallelbooltrueRun tests in parallel

[publish] Section​

Publishing configuration.

[publish]
# Registry URL
registry = "https://registry.morphir.dev"

# Include patterns
include = [
"src/**/*.elm",
"morphir.toml",
"README.md",
"LICENSE"
]

# Exclude patterns
exclude = [
"**/*.test.elm",
"**/Internal/**"
]

Fields​

FieldTypeDefaultDescription
registrystringDefault registryRegistry URL
includearrayStandard filesFiles to include
excludearray[]Files to exclude

Complete Example​

Single Project​

[morphir]
version = "^4.0.0"

[project]
name = "my-org/order-domain"
version = "1.0.0"
description = "Order processing domain model"
authors = ["Jane Doe <jane@example.com>"]
license = "Apache-2.0"
source_directory = "src"
exposed_modules = ["Domain.Order", "Domain.Product", "Domain.Customer"]

[frontend]
language = "elm"

[frontend.elm]
elm_version = "0.19"

[codegen]
targets = ["typescript", "scala"]

[codegen.typescript]
module_format = "esm"

[codegen.scala]
package_prefix = "com.myorg.orders"

[dependencies]
"morphir/sdk" = "^3.0.0"
"my-org/common-types" = { path = "../common-types" }

[dev-dependencies]
"morphir/test-utils" = "^1.0.0"

[tasks.ci]
description = "CI pipeline"
depends = ["check", "test", "build", "codegen"]

Workspace​

[morphir]
version = "^4.0.0"

[workspace]
members = ["packages/*", "apps/*"]
exclude = ["packages/deprecated-*"]
default_member = "packages/core"
out_dir = ".morphir/out"

# Shared settings inherited by all projects
[frontend]
language = "elm"

[frontend.elm]
elm_version = "0.19"

[codegen]
targets = ["typescript"]

# Shared dependencies
[dependencies]
"morphir/sdk" = "^3.0.0"

[extensions]
spark-codegen = { path = "./extensions/spark-codegen.wasm" }

[tasks.ci]
description = "Workspace CI"
depends = ["check", "test", "build"]

Validation Rules​

Required Fields​

ModeRequired Sections/Fields
Project[project], project.name, project.version
Workspace[workspace], workspace.members

Naming Constraints​

FieldConstraint
project.name^[a-z][a-z0-9-]*/[a-z][a-z0-9-]*$
project.versionValid semver
Module namesPascalCase, dot-separated

Path Constraints​

FieldConstraint
source_directoryMust exist, relative path
dependencies.*.pathMust contain morphir.toml

Error Messages​

ErrorDescription
E001Missing required field
E002Invalid package name format
E003Invalid version format
E004Source directory not found
E005Circular dependency detected
E006Unknown extension
E007Invalid glob pattern
E008Duplicate project name in workspace