Start from a preset
Quest step uses the impossible trigger, so only your own command completes it. Recipe unlock exists to put a custom recipe into the recipe book. Hunt challenge completes when the player kills a chosen mob.
Advancements are the closest thing vanilla has to a quest system. They chain into trees, show a toast when completed, and can hand out experience, unlock recipes or run a function. This builder writes the JSON and the /advancement grant line to fire it.
Advancements live inside a data pack. The data pack generator builds the folder if you do not have one.
A root advancement starts its own tab in the advancements screen. Give it a parent instead and it becomes a step in that parent's tree.
Unlocking a recipe here is how a custom recipe finally appears in the recipe book. That is the whole job of most vanilla advancements you never see.
Save as
With the impossible trigger this is the only way it completes, which is exactly what you want when a quest step is finished by your own logic rather than by the world.
Fill in the file, display, trigger and rewards; the JSON, its path and a grant command update as you type.
Quest step uses the impossible trigger, so only your own command completes it. Recipe unlock exists to put a custom recipe into the recipe book. Hunt challenge completes when the player kills a chosen mob.
Namespace and file name give the path and the ID. Leave the parent empty and the advancement becomes a root with its own tab and background; enter a parent ID such as harbor:harbor_quest_1 and it becomes a step in that tree.
Title, description and icon are what players see. The frame matters too: task is a plain square, goal is rounded, and challenge gets a spiked frame and its own toast and sound. Toast, chat announcement and hidden are switches.
impossible never fires by itself. tick fires on the next tick for every player, which suits a root that should be visible from the start. player_killed_entity waits for a kill of the entity type you name.
Experience, a function that runs as the player, and recipes to unlock. The grant command below the JSON completes the advancement by hand.
An advancement whose parent ID does not exist is not loaded at all. Check the parent path when a step never appears.
A hidden advancement stays out of the screen, together with all its children, until it is completed.
Announce in chat is on by default. On a busy server, turn it off for small steps and keep it for the ones worth celebrating.
Java Edition 1.20 to 26.3. 1.20.5 renamed the icon field from item to id, and the folder is advancement from 1.21 and advancements before; the version selector handles both. To repeat a test, /advancement revoke @s only <id> takes it back, and the rewards run again on the next grant.