Skip to content

Examples

A first recipe, then the PKL language features you actually need. Full language docs live in the PKL language reference.

Your first recipe

Create config/pkl4mc/data/mypack/recipes/stick_frenzy.pkl:

config/pkl4mc/data/mypack/recipes/stick_frenzy.pkl
amends "@pkl4mc/recipes.pkl"

shaped {
  new {
    name = "stick_frenzy"
    category = "misc"
    key {
      ["S"] { item = "minecraft:stick" }
    }
    pattern { "S S"; " S "; "S S" }
    output { item = "minecraft:stick"; count = 4 }
  }
}

Run /pkl reload in-game (op required). Craft 5 sticks into 4. Your recipe is live.

Now break it on purpose: change pattern to patern, reload, and run /pkl errors. You get the file, line, column, and error message. With IDE setup done, the same error shows as a red squiggle before you ever launch the game.

Amending a schema

amends means “this file fills in the fields of that schema”:

amends "@pkl4mc/recipes.pkl"

The schema defines fields, types, and JSON rendering. You set values. The schema catalog lists everything you can amend.

Objects and collections

// object: braces, fields separated by newlines or ;
output { item = "minecraft:stick"; count = 4 }

// listing: elements one per line
pattern {
  "S S"
  " S "
  "S S"
}

// listing of objects: each element wrapped in new { }
shaped {
  new { name = "recipe_one" /* ... */ }
  new { name = "recipe_two" /* ... */ }
}

// mapping: string keys in brackets
key {
  ["S"] { item = "minecraft:stick" }
}

Variables and reuse

local declares a file-private value. Define once, use everywhere:

amends "@pkl4mc/recipes.pkl"

local steel = "gtceu:steel_ingot"

smelting {
  new {
    name = "steel_from_iron"
    input { item = "minecraft:iron_ingot" }
    output { item = steel }
    experience = 0.7
    cookingTime = 200
  }
}

String interpolation uses \(expr):

local mod = "mypack"
name = "\(mod)_steel_recipe"

Mod conditions

The loaded Forge mod list is available to every file. Branch on mod presence:

local loadedMods = read("prop:pkl4mc.loadedMods").split(",")
local hasProjectE = loadedMods.contains("projecte")

shapeless {
  new {
    name = "conditional_example"
    inputs {
      new { item = if (hasProjectE) "minecraft:diamond" else "minecraft:coal" }
    }
    output { item = "minecraft:emerald" }
  }
}

when inserts elements conditionally inside collections:

inputs {
  new { item = "minecraft:coal" }
  when (hasProjectE) {
    new { item = "minecraft:diamond" }
  }
}

Types catch your typos

Schema fields are typed. A misspelled field or count = "four" is an evaluation error and a red squiggle in your editor, not a silent in-game failure. After running the dump command, item id strings validate against your modpack’s real registries too.

Raw modules

Modules written from scratch, without amending a schema, must declare JSON output themselves:

output { renderer = new JsonRenderer {} }

Schemas declare this for you. Mods without a dedicated schema are covered by the generic recipes schema.