Getting Started
This guide takes you from zero to a real development workflow with Kore. Instead of stopping at a minimal "hello world," you will build a small but structured datapack, run it in-game, iterate quickly, and learn how to scale your project.
If you already have solid datapack experience and want an architecture-first migration guide, jump to From Datapacks to Kore.
What you will build
By the end of this page, you will have:
- A Kotlin project configured for Kore.
- A datapack with metadata and multiple functions.
- A simple game loop entry point (
load+ user-triggered functions). - A practical local development cycle to edit, regenerate, and test quickly.
- A clean starting structure you can keep expanding.
Prerequisites
- Java 21 (JDK 21) or higher.
- Gradle (wrapper recommended:
./gradlew). - IntelliJ IDEA (recommended) or another IDE with Kotlin support.
- Basic understanding of Minecraft datapacks (helpful but not required).
Kotlin basics you need before Kore
If you are new to Kotlin, do not worry. You only need a small subset to be productive with Kore.
val and var
valmeans read-only reference (preferred by default).varmeans mutable reference (use only when reassignment is needed).
Functions
You declare functions with fun. Kore code is mostly function calls inside builders.
Null safety
Kotlin distinguishes nullable (String?) and non-null (String) types.
Use:
?.for safe calls,?:for fallback values (Elvis operator).
Lambdas and builder blocks
Kore uses Kotlin lambdas heavily:
The { ... } block is a lambda, and inside it Kore exposes a DSL context with helper functions.
Extension functions (very important in Kore projects)
Kotlin lets you add functions to existing types without inheritance. This is ideal for structuring large datapacks.
You can then call registerWelcome() inside your dataPack {} builder.
Step 1: Create your project
You have two ways to start.
Option A: Use the Kore Template (recommended)
The fastest option is the template repository, which is already configured for Kotlin + Gradle + Kore.
- Open Kore Template.
- Click "Use this template" (or clone directly).
- Open it in IntelliJ IDEA.
- Let Gradle sync.
- Run the
mainfunction insrc/main/kotlin/Main.kt.
Option B: Add Kore to an existing Kotlin project
If you already have a Kotlin project, add Kore manually.
Core modules
kore- core DSL to generate datapacks.oop- object-oriented gameplay abstractions.helpers- helper utilities built on top of Kore.bindings- experimental importer for existing datapacks.
For your first datapack, use only kore.
Gradle Kotlin DSL
Gradle Groovy DSL
Snapshot builds (latest unreleased changes)
If you want bleeding-edge features:
Kotlin compiler and JVM settings
Kore relies on context parameters. Make sure your build.gradle.kts contains:
Step 2: Write a first useful datapack
Instead of a single command, create a tiny but realistic pack with:
- metadata (
pack), - one function for player feedback,
- one function for setup behavior.
If you are new to Kotlin syntax, read the code like this:
val datapack = ...stores the generated datapack object.dataPack("starter_kore") { ... }creates a builder context.- each
function("...") { ... }block writes one generated.mcfunctionfile.
Create Main.kt:
Run main, then put the generated zip into your world's datapacks folder.
Step 3: Load and test in Minecraft
- Open your world.
- Run
/reload. - Trigger the function:
If everything is correct, chat displays your message.
Step 4: Use load {} as your real entry point
In Kore, using load {} is usually better than manually naming a startup function and wiring tags yourself. It directly creates and registers a function in minecraft:load, which makes your startup flow explicit and less error-prone.
Most datapacks become easier to maintain when you separate:
- initialization (
load), - recurring logic (
tickwhen needed), - feature functions (your own namespaced functions).
Add this structure in Kore by defining dedicated functions and using consistent names:
With this approach:
load("bootstrap")runs once after/reload.tick("runtime/checks")runs every game tick.function("feature/...")stays your reusable API surface.- folder-like names keep generated files organized as the project grows.
Step 5: Organize code before it gets messy
A common beginner mistake is placing everything in one main function. Prefer small helpers and focused files early.
Example using extensions:
This pattern scales much better than one giant builder block.
Step 6: Use a fast development loop
During development, your loop should be:
- Edit Kotlin code.
- Re-run
main. - Copy or regenerate output into your world datapack folder.
- In-game:
/reload. - Run the function you are testing.
Tips:
- Use
.generate()when you want to inspect generated files locally. - Use
.generateZip()when you want easy distribution. - Enable pretty JSON in Configuration when debugging generated resources.
Step 7: Build an advanced mini-pack with a custom enchantment
At this point, create a pack that is closer to production structure:
- startup flow with
load, - runtime flow with regular functions,
- one custom data-driven feature (a custom enchantment).
Example:
What this gives you:
- a generated
data/starter_kore/enchantment/vampiric.json, - startup player feedback via
minecraft:load, - a clear split between command functions and data-driven definitions.
To validate in-game:
- Regenerate your datapack.
- Put it in your world.
- Run
/reload. - Check logs/chat for load output.
- Test enchantment behavior with commands or controlled test scenarios.
Going beyond a minimal datapack
Once your first commands work, move to data-driven features:
- Add recipes, loot tables, predicates, and tags.
- Create multiple function entry points per feature.
- Separate "bootstrap" code from "gameplay" code.
- Reuse helper functions to avoid duplicated command blocks.
Good expansion ideas after the custom enchantment:
- A welcome system with per-player conditions.
- A starter kit function with basic inventory setup.
- A scoreboard-based progression mechanic.
- A custom recipe that complements your enchantment.
- A balancing pass for enchantment costs, rarity, and max level.
Kotlin tips that matter specifically in Kore projects
- Prefer
valby default; immutable declarations reduce accidental state issues. - Use extension functions on
DataPackto keep your DSL composable. - If your IDE imports the wrong DSL symbol, qualify temporarily with
this.in the builder scope, then fix the import. - Keep function names and file-like paths consistent (
feature/x,system/y) to keep generated output predictable. - Re-declaring the same logical entry in Kore is idempotent: the last declaration wins.
- Prefer
load {}andtick {}builders over manual tag wiring for standard lifecycle hooks.
Quick Kotlin learning resources
- Kotlin documentation
- Kotlin null safety
- Kotlin extensions
- Learn X in Y Minutes - Kotlin
- Kotlin Playground
Troubleshooting
Unresolved Kore DSL symbols
- Check that the dependency exists in the correct module.
- Verify the compiler flag
-Xcontext-parameters. - Refresh/sync Gradle in your IDE.
Java/Kotlin toolchain errors
- Confirm JDK 21 is installed and selected by Gradle.
- Confirm
jvmToolchain(21)is configured.
Datapack generates but does not work in-game
- Confirm the namespace/function path in
/function. - Run
/reloadafter every regeneration. - Check the world folder path and datapack placement.
- Open logs and verify no JSON or command syntax error is reported.
Recommended learning path after this guide
Start here next:
For the full index, see Home.
