Skip to content

Import System

The import system allows you to organize DataSheetLang projects into reusable packages with namespaced exports.

A workspace defines the packages available to your project. Create a datasheetlang.yml file (or .datasheetlang.yml for hidden) in your project root.

workspace:
packages:
<name>: <path>
schemaAliases:
<alias>: <schema>
defaultImports:
- <package>
PropertyTypeDescription
packagesmap[string, string]Maps package names to their folder paths (relative to workspace file)
schemaAliasesmap[string, string]Maps short schema names to full schema identifiers
defaultImportslist[string]Packages to import automatically in all specs
workspace:
packages:
core: ./packages/core
shared: ./packages/shared
vendor: ../external/vendor-lib
schemaAliases:
items: items.v1
equipment: equipment.v2
defaultImports:
- core

The workspace file is discovered by walking up the directory tree from the spec file location. The first datasheetlang.yml or .datasheetlang.yml found becomes the workspace root.

If both visible and hidden files exist in the same directory, the visible file takes precedence.

Package names are identifiers used in imports and script references:

  • Must be defined in workspace.packages
  • Case-sensitive
  • Used as namespace prefix for exports (e.g., core.weapon.base)

Each package must have an index.yml file in its root folder. This is the package entry point that gets loaded when the package is imported.

packages/core/ # Package folder
└── index.yml # Entry point (required)

Package paths in the workspace config are resolved relative to the workspace file:

workspace:
packages:
core: ./packages/core # Relative path
vendor: ../external/vendor # Parent directory

Import a registered package by name:

imports:
- from: core
- from: shared

This loads the package’s index.yml and makes all exported definitions available. Variables require explicit opt-in — see Selective variable imports.

Import a specific file using a relative path:

imports:
- from: ./scripts/common.yml
- from: ../shared/utils.yml

Relative imports are resolved from the importing file’s directory.

Variables require explicit opt-in via use.variables. An import without use.variables does not import any variables, even if the source module exports them:

imports:
- from: shared
use:
variables:
- BASE_HP
- BASE_MP

Only the listed variable names are imported. Requesting a variable not in the source module’s exports.variables triggers E536.

Local variables shadow imported variables of the same name. See Variables for full documentation.

Packages can import other packages. When you import a package, its dependencies are also resolved.

When you import a package that imports another package, its dependencies are also loaded automatically.

Export definitions for use in other modules:

exports:
definitions:
- baseCondition
- rareCondition

Exported names must exist in the module’s definitions: section (E512 if not). See Definitions for usage with $extends.

Export variables for use in other modules:

exports:
variables:
- BASE_HP
- BASE_MP

Exported names must exist in the module’s variables: section or its effective imported scope — variables explicitly imported via use.variables (E535 if not). This enables variable re-export: a module can import a variable and make it available to its own consumers. See Variables for full syntax and examples.

Scripts are reusable operation blocks:

exports:
scripts:
starter.gear:
items:
create:
- id: 100
name: training_sword
equipment:
create:
- equipmentId: 100
level: 1
part: Weapon

Scripts can contain operations for multiple entity types (items, equipment).

The use directive injects script operations into your spec:

imports:
- from: core
use:
- core.starter.gear
- core.event.items

Operations are merged in this order:

  1. Script operations (in order listed in use)
  2. Local operations (defined in the spec file)

This allows scripts to create base items while local operations modify them:

use:
- core.base.items # Creates items first
items:
update: # Then updates are applied
- id: 100
changes:
buyPrice: 999

When resolving an import:

  1. Check if it’s a relative path (starts with ./ or ../)
  2. If relative, resolve from the importing file’s directory
  3. If not relative, look up in the package registry

The system detects and prevents circular imports:

packages/pkgA/index.yml
imports:
- from: pkgB # pkgA imports pkgB
# packages/pkgB/index.yml
imports:
- from: pkgA # pkgB imports pkgA → ERROR: E403

All loaded modules are tracked in a dependency graph. Each module is loaded only once, even if imported multiple times.

CodeErrorCause
E401Unknown packagePackage name not found in workspace registry
E402Module not foundFile path does not exist
E403Circular importImport chain creates a cycle
E405Duplicate package pathTwo packages resolve to the same directory
E410Duplicate exportSame export name defined in multiple files
E414Import escapes packageRelative import resolves outside package root
E420Script not foundReferenced script does not exist
E535Exported variable not foundVariable in exports.variables not in local variables: or effective imported scope
E536Imported variable not exportedVariable in use.variables not in source’s exports.variables
imports:
- from: nonexistent # E401: Package 'nonexistent' is not registered

Fix: Add the package to workspace.packages or check for typos.

E403: Circular import detected: pkgA → pkgB → pkgA

Fix: Restructure packages to eliminate circular dependencies.

E405: Duplicate package path - packages 'weapons' and 'arms' both resolve to:
D:\project\packages\weapons

Fix: Ensure each package has a unique directory path in your workspace config.

E410: Duplicate export 'starter.gear' - already defined in core/scripts.yml

Fix: Rename one of the conflicting exports or consolidate them.

packages/weapons/index.yml
imports:
- from: ../../outside.yml # E414: Resolves outside package root

Fix: Relative imports within a package must stay within the package directory. Use a package import for external files.

use:
- core.nonexistent.script # E420: Script 'core.nonexistent.script' not found

Fix: Check the script name and ensure the package is imported.

datasheetlang.yml

workspace:
packages:
core: ./packages/core
shared: ./packages/shared
defaultImports:
- core

packages/core/index.yml

imports:
- from: ./scripts/common.yml
exports:
scripts:
common.items:
items:
create:
- id: 1
name: common_item
maxStack: 1

packages/core/scripts/common.yml

exports:
scripts:
weapons.starter:
items:
create:
- id: 100
name: training_sword
combatItemType: EquipWeapon
category: Lance

packages/shared/index.yml

imports:
- from: core
exports:
scripts:
bonus.rewards:
items:
create:
- id: 90001
name: bonus_sword
combatItemType: EquipWeapon
category: Dual

patches/bonus-items.yml

spec:
schema: items
imports:
- from: shared
use:
- shared.bonus.rewards
items:
update:
- id: 90001
changes:
buyPrice: 0
tradable: "False"