Skip to content

Setting Up Packages

Packages let you organize reusable scripts into self-contained modules. This guide walks you through setting up a workspace with packages.

As your project grows, you’ll want to:

  • Namespace exports to avoid naming collisions between teams
  • Share scripts that define common item sets or equipment configurations
  • Organize by domain (e.g., core, shared, extensions)

A typical DataSheetLang project with packages looks like this:

my-project/
├── datasheetlang.yml # Workspace configuration
├── packages/
│ ├── core/
│ │ └── index.yml # Core package entry point
│ └── shared/
│ └── index.yml # Shared package entry point
└── patches/
└── items.yml # Your spec files

Create datasheetlang.yml in your project root:

workspace:
packages:
core: ./packages/core
shared: ./packages/shared

Each entry maps a package name to its folder path. The path is relative to the workspace file.

Create your first package at packages/core/index.yml:

exports:
scripts:
weapon.starter:
items:
create:
- id: 51056
name: chain_scythe
combatItemType: EquipWeapon
category: Lance
maxStack: 1
tradable: "False"
level: 60

The index.yml file is the package entry point. Everything under exports becomes available to other files that import this package.

Create a spec file at patches/items.yml:

spec:
schema: items
imports:
- from: core
use:
- core.weapon.starter
items:
update:
- id: 51056
changes:
buyPrice: 100

Key points:

  • imports: [from: core] loads the core package
  • Scripts are referenced with the package prefix: core.weapon.starter

Packages export scripts as reusable blocks of operations:

packages/core/index.yml
exports:
scripts:
reaper.weapons:
items:
create:
- id: 51056
name: chain
combatItemType: EquipWeapon
maxStack: 1
level: 60
- id: 51057
name: scythe
combatItemType: EquipWeapon
maxStack: 1
level: 60

Use scripts with the use directive:

patches/reaper-patch.yml
spec:
schema: items
imports:
- from: core
use:
- core.reaper.weapons
items:
update:
- id: 51056
changes:
buyPrice: 445360

When compiled, script operations are injected before your local operations. This lets you define base items in a script and apply modifications locally.

Packages can split their exports across multiple files:

packages/core/
├── index.yml
└── scripts/
├── weapons.yml
└── starter-gear.yml

Use relative imports to combine them:

packages/core/index.yml
imports:
- from: ./scripts/weapons.yml
- from: ./scripts/starter-gear.yml
exports:
scripts:
common.items:
items:
create:
- id: 1
name: general_item
maxStack: 1

Each imported file can have its own exports section. All exports are collected and namespaced under the package name.

Packages can export named variables (ID constants, shared values) alongside scripts. Variables require explicit opt-in at every step — see Variables: Cross-module variables for full rules.

Declare variables and list them in exports.variables:

packages/constants/index.yml
variables:
BASE_HP: 1000
BASE_MP: 500
exports:
variables:
- BASE_HP
- BASE_MP

Consumer specs import with use.variables:

imports:
- from: constants
use:
variables:
- BASE_HP
creatures:
create:
- id: 1
hp: $BASE_HP

Variables can be split across sub-files. Each sub-file must declare spec:, define variables, and export them. The index.yml imports with use.variables and re-exports:

packages/crystals/
├── index.yml
├── weapon.yml
└── armor.yml

Sub-file (weapon.yml):

spec:
version: "1.0"
variables:
SWORD_ID: 8100
AXE_ID: 8200
exports:
variables:
- SWORD_ID
- AXE_ID

Package entry (index.yml):

spec:
version: "1.0"
imports:
- from: ./weapon.yml
use:
variables:
- SWORD_ID
- AXE_ID
- from: ./armor.yml
use:
variables:
- CHEST_ID
exports:
variables:
- SWORD_ID
- AXE_ID
- CHEST_ID

Consumer spec:

imports:
- from: crystals
use:
variables:
- SWORD_ID
items:
upsert:
- id: $SWORD_ID
level: 60

Key points:

  • Sub-files need spec: version: "1.0" to be recognized as modules
  • Sub-files must list exported variables in exports.variables
  • index.yml must explicitly import each variable via use.variables before re-exporting
  • An import without use.variables imports no variables — definitions auto-import, variables do not

You can import from multiple packages:

imports:
- from: core
- from: shared
use:
- core.weapon.starter
- shared.special.weapons

Each package maintains its own namespace, so core.weapon.starter and shared.weapon.starter are distinct scripts.

Here’s a complete working setup:

datasheetlang.yml

workspace:
packages:
core: ./packages/core

packages/core/index.yml

exports:
scripts:
starter.weapons:
items:
create:
- id: 100
name: training_sword
combatItemType: EquipWeapon
category: Lance
maxStack: 1
level: 1
starter.equipment:
equipment:
create:
- equipmentId: 100
level: 1
part: Weapon

patches/new-player.yml

spec:
schema: items
imports:
- from: core
use:
- core.starter.weapons
- core.starter.equipment
items:
update:
- id: 100
changes:
buyPrice: 0
sellPrice: 0

Run with:

Terminal window
dsl apply patches/new-player.yml --datasheet ./DataSheet