Packages compose through explicit dependencies and cross-package references. Understanding the dependency model prevents installation failures and reference errors.

The dependsOn Array

Every package declares its dependencies in the dependsOn array. Each entry specifies a packageKey that must be present and installed before this package can install.

{
  "dependsOn": [
    { "packageKey": "core" },
    { "packageKey": "core_business_glossary" }
  ]
}

The installation engine resolves the full dependency tree before executing any loaders. If any dependency is missing or not in the correct state, installation halts with a dependency error.

Transitive Dependencies

Dependencies are not transitive. If package C depends on package B, and package B depends on package A, package C must explicitly declare both B and A in its dependsOn array if it references assets from both. Relying on B’s dependency on A is insufficient — the validation engine checks only direct dependsOn entries when resolving cross-package references.

{
  "key": "cust_analytics_dashboards",
  "dependsOn": [
    { "packageKey": "core" },
    { "packageKey": "core_code_lists" },
    { "packageKey": "core_data_product" }
  ]
}
Warning

Dependencies must be in INSTALLED state. A package that is CREATED, VALIDATED, or VERSIONED does not satisfy the dependency requirement. Validate and install dependencies first.

Cross-Package Reference Syntax

Assets reference entities from other packages using the format {packageKey}#{assetKey}:

{
  "attributeTypes": [
    {
      "key": "custom_rating",
      "extends": "core#attribute_integer"
    }
  ]
}

This syntax appears throughout the package model: in attributeTypes, relationTypes, components, icons, templates, and any other asset that can reference external entities.

The resolver splits the reference at #, looks up the package key in the installed package registry, then resolves the asset key within that package’s key-to-ID mapping. If either lookup fails, validation reports a reference error.

Reference Contexts

Cross-package references appear in several contexts, each with specific behavior:

ContextExampleBehavior
Attribute extends"extends": "core#attribute_integer"Inherits base attribute properties. Child attribute overrides specific fields.
Template component"value": "core#ownership_generic"Embeds the referenced component in the template layout.
Relation type endpoint"targetObjectType": "core_glossary#business_term"Defines which object type appears on the target end of the relation.
Icon reference"icon": "core#icon_document"Uses the referenced icon for visual representation.
Codetable reference"codetable": "core#status_list"Binds an attribute to a shared codetable for value selection.

Local References

Assets within the same package omit the package key prefix. A reference to description (without #) resolves against the current package. A reference to core#description (with #) resolves against the core package. Ambiguity between local and cross-package references is resolved by the presence or absence of the # separator.

Standard Package Hierarchy

The core package is the foundation. All other packages depend on it directly or transitively.

core (foundation)
├── core_code_lists
│   └── Connector packages (core_snowflake, core_power_bi, core_tableau, ...)
├── core_data_product
│   └── Relationship bridges (core_relations_data_products_*)
├── core_business_glossary
├── core_key_performance_indicators
│   └── KPI bridges (core_relations_kpi_*)
├── core_logical_model
└── core_documentation

Core Package

Provides the foundational asset types that all other packages build on: base attribute types (core#attribute_string, core#attribute_integer, core#attribute_date), shared components (core#ownership_generic, core#comments_generic), base icons, colors, and the default workflow.

Domain Packages

Each domain package (core_business_glossary, core_data_product, core_logical_model, etc.) defines a complete set of object types, attributes, templates, and translations for one metadata domain. Domain packages depend on core and optionally on core_code_lists.

Connector Packages

Connector packages (core_snowflake, core_power_bi, core_tableau) extend the platform with external system integrations. They depend on core_code_lists for shared codetable definitions and define integration-specific object types, API mappings, and query sets.

Relationship Bridge Packages

Bridge packages (core_relations_data_products_*, core_relations_kpi_*) define cross-domain relations. They depend on core plus both domain packages they connect. Most use autoInstall: true for automatic deployment.

Package Types

Typetype field valuePurpose
Regular"regular" (default, can be omitted)Full package with assets. Declares its own object types, attributes, templates, and other entities.
Patch"patch"Incremental update to an existing package. Requires basePackageKey and runAfter.
Automation"automation"Contains only triggers and actions. No structural metadata assets.

Regular Packages

The default package type. Contains a complete set of assets that define a domain: object types, attribute types, relation types, templates, translations, and supporting codetable entries. Most packages in the hierarchy are regular packages.

When the type field is omitted from the package JSON, the system treats the package as regular. Explicitly setting "type": "regular" has the same effect.

Patch Packages

A patch modifies or extends an existing installed package without replacing it. Two fields control patch behavior:

  • basePackageKey — Identifies the target package this patch modifies.
  • runAfter — Specifies which package (base or another patch) must be installed before this patch.
{
  "type": "patch",
  "basePackageKey": "core_business_glossary",
  "runAfter": "core_business_glossary"
}

Multiple patches to the same base package form an ordered chain through runAfter. Each patch declares the previous patch (or the base) as its prerequisite.

core_business_glossary (base)
  → core_business_glossary_patch_01 (runAfter: core_business_glossary)
    → core_business_glossary_patch_02 (runAfter: core_business_glossary_patch_01)

Patches share the base package’s key-to-ID mapping. A patch can modify existing entities by redeclaring them with the same key, or add new entities with new keys.

What Patches Can Do

  • Add new attributes, relations, or templates to the base package’s object types.
  • Modify properties of existing assets (labels, validation rules, default values).
  • Add new object types that extend the base package’s domain.
  • Update translations for existing or new assets.

What Patches Cannot Do

  • Remove assets defined in the base package. Deletion requires a new version of the base package.
  • Change the type of an existing attribute (e.g., string to integer). This requires delete and recreate.
  • Modify another patch’s assets directly. Each patch targets the base package only.

Automation Packages

Contain trigger and action definitions only. No object types, attributes, or templates. Used for event-driven workflows that react to metadata changes. Automation packages depend on the domain packages whose events they subscribe to.

Relationship Packages

Relationship packages are a specialized pattern for connecting two domain packages. They follow strict conventions:

  • autoInstall: true — The system installs them automatically when both domain packages are present.
  • Assets — Contain only objectTypeRelations definitions. No object types, attributes, or templates.
  • Dependencies — Always exactly three: core, the source domain package, and the target domain package.
{
  "key": "core_relations_data_products_glossary",
  "autoInstall": true,
  "dependsOn": [
    { "packageKey": "core" },
    { "packageKey": "core_data_product" },
    { "packageKey": "core_business_glossary" }
  ]
}

Auto-install triggers during the installation of either domain package. If package A is already installed and package B installs, the system detects that the relationship package’s dependencies are now satisfied and installs it automatically.

Naming Convention

Relationship packages follow the pattern core_relations_{source}_{target}. The source and target refer to the domain packages being connected, not the object types. A single relationship package may define multiple objectTypeRelations between different object types in the two domains.

Patch Ordering

The runAfter field creates a strict total order among patches targeting the same base package. The installation engine sorts patches by their runAfter chain and executes them sequentially.

Rules for patch ordering:

  • The first patch in a chain sets runAfter to the basePackageKey.
  • Each subsequent patch sets runAfter to the previous patch’s key.
  • Skipping a patch in the chain is not supported — the full chain must install in order.
  • A patch cannot declare runAfter pointing to a patch targeting a different base package.

Gotchas

Warning

Dependency state matters. A dependency package in VALIDATED or VERSIONED state does not satisfy the requirement. The dependency must reach INSTALLED state before the dependent package can install. Check the version state in the package management UI.

Warning

Renaming an asset key is a breaking change. Renaming a key is equivalent to deleting the old asset and creating a new one. All cross-package references using the old key ({packageKey}#{oldKey}) break immediately. To rename safely, create the new key, migrate all references, then remove the old key in a subsequent patch.

Warning

Circular dependencies are not detected automatically. If package A depends on package B and package B depends on package A, the installation ordering algorithm may loop indefinitely. Review the dependency tree manually before adding new dependsOn entries.

Tip

Use the cust_ prefix for custom packages to distinguish them from core_ packages. This convention prevents key collisions and makes it clear which packages are platform-provided versus tenant-specific.

Dependency Resolution Summary

The installation engine resolves dependencies using these rules in order:

  1. Build the full dependency graph from dependsOn entries.
  2. Topological sort to determine installation order.
  3. Verify each dependency is in INSTALLED state.
  4. Detect and install eligible autoInstall relationship packages.
  5. Sort patches by runAfter chain within each base package.
  6. Execute loaders for each package in the resolved order.

If any step fails, the engine halts and reports the specific failure — missing dependency, state violation, or ordering conflict.