Wiki 9Minecraft Wiki 9Minecraft

Rain Detection Command Recipe

Detect active rain or thunderstorms in a Bedrock behavior pack and run commands in response.

6Sections
4Code examples
4Known errors

Minecraft Bedrock Edition does not have a target selector argument or `/execute if` condition that directly checks the current weather. When your add-on needs to run function commands only while it is raining—such as buffing aquatic mobs, extinguishing campfires, or triggering ambient sound effects—you must bridge the gap using either an entity sensor, a Molang query in an animation controller, or a physical block detector in the world. This page covers the most reliable patterns for detecting rain and routing that signal into your command systems.

Choosing a Detection Approach

Because `/weather query` prints a message to the chat window rather than returning a value that `/execute` can read in a function file, pure command packs have to rely on indirect observation. If you are building a strictly vanilla map with command blocks and no behavior pack files, your only option is a physical world mechanism that reacts to precipitation from the sky.

When you are working inside a behavior pack, you have far better tools. The game engine exposes weather state to entity filters and to some degree through environmental reactions. The cleanest way to turn rain into a scoreboard value or a function call is to create a dedicated, invisible marker entity or attach a behavior component to existing entities—like `minecraft:player`—that fires an event when the weather changes.

Before writing any files, decide whether you need global weather detection or local rain contact. Global detection asks whether the Overworld weather cycle is currently set to rain or thunder, regardless of whether the target is standing in a desert or under a roof. Local contact asks whether rain drops are actually hitting a specific position in the world, which requires an unobstructed view of the sky and a biome where precipitation actually falls.

MethodScopeBest Used For
Entity `weather_at_position` filterLocal or GlobalBehavior packs that need immediate, tick-accurate command execution.
Entity `is_in_water_or_rain` filterLocal contactApplying effects to players or mobs physically standing out in the rain.
Cauldron or Fire block observerLocal sky accessCommand-block-only worlds where behavior packs cannot be installed.

Method 1: Entity Environment Sensor and Filters

The most direct way to trigger commands during rain in a behavior pack is the `minecraft:environment_sensor` component. This component evaluates entity filters every tick and fires an entity event as soon as a filter passes. By pairing that event with the `queue_command` response—or by adding a tag that your `tick.json` functions check—you can bridge entity state directly into your function system.

Bedrock provides two primary filters for this purpose: `is_in_water_or_rain` and `weather_at_position`. The `is_in_water_or_rain` filter returns true if the entity is touching water or is exposed to falling rain. If you want to isolate rain specifically, you must combine it inside an `all_of` block with a negated `is_in_water` filter so that swimming in a river does not give you a false positive.

If you instead want to check the weather state at the entity's coordinates without worrying about water, use `weather_at_position`. It checks the weather at the block position of the subject entity. Note that in dry biomes such as deserts and savannas, positional weather checks can evaluate differently than in biomes where rain visually falls, so always test your sensor in the specific biomes your players will visit.

BP/entities/player.json
{
  "format_version": "1.20.40",
  "minecraft:entity": {
    "description": {
      "identifier": "minecraft:player",
      "is_spawnable": false,
      "is_summonable": false
    },
    "components": {
      "minecraft:environment_sensor": {
        "triggers": [
          {
            "filters": {
              "all_of": [
                {
                  "test": "is_in_water_or_rain",
                  "subject": "self",
                  "operator": "==",
                  "value": true
                },
                {
                  "test": "is_in_water",
                  "subject": "self",
                  "operator": "==",
                  "value": false
                },
                {
                  "test": "has_tag",
                  "subject": "self",
                  "operator": "!=",
                  "value": "in_rain"
                }
              ]
            },
            "event": "addon:enter_rain"
          },
          {
            "filters": {
              "all_of": [
                {
                  "test": "is_in_water_or_rain",
                  "subject": "self",
                  "operator": "==",
                  "value": false
                },
                {
                  "test": "has_tag",
                  "subject": "self",
                  "operator": "==",
                  "value": "in_rain"
                }
              ]
            },
            "event": "addon:leave_rain"
          }
        ]
      }
    },
    "events": {
      "addon:enter_rain": {
        "sequence": [
          {
            "run_command": {
              "command": [
                "tag @s add in_rain",
                "function weather/on_rain_start"
              ]
            }
          }
        ]
      },
      "addon:leave_rain": {
        "sequence": [
          {
            "run_command": {
              "command": [
                "tag @s remove in_rain",
                "function weather/on_rain_stop"
              ]
            }
          }
        ]
      }
    }
  }
}

Distinguishing Rain from Thunderstorms

Sometimes your command recipe needs to know not just whether water is falling from the sky, but whether the world is experiencing a normal rain shower or a full thunderstorm. The `weather_at_position` filter accepts string values such as `clear`, `rain`, and `thunder`. Unlike `is_in_water_or_rain`, which is a simple boolean contact check, `weather_at_position` lets you branch your logic into three distinct states.

When using `weather_at_position`, keep in mind that the check still cares about the location of the entity running the filter. If a player walks under a solid roof, a positional check may evaluate as `clear` depending on how the engine resolves sky cover for that block column. To build a true global weather detector that ignores roofs, summon a dedicated marker entity high up in the air inside a ticking area where no blocks can ever be placed above it.

In the example below, a custom dummy entity sits in a ticking area and updates a global scoreboard objective called `weather_state` (`0` for clear, `1` for rain, `2` for thunder). Notice how each trigger checks a tag on the entity itself to stop the `environment_sensor` from running the command twenty times per second while the weather stays the same.

BP/entities/weather_watcher.json
{
  "format_version": "1.20.40",
  "minecraft:entity": {
    "description": {
      "identifier": "addon:weather_watcher",
      "is_spawnable": false,
      "is_summonable": true
    },
    "components": {
      "minecraft:collision_box": {
        "width": 0.0,
        "height": 0.0
      },
      "minecraft:physics": {
        "has_gravity": false,
        "has_collision": false
      },
      "minecraft:pushable": {
        "is_pushable": false,
        "is_pushable_by_piston": false
      },
      "minecraft:environment_sensor": {
        "triggers": [
          {
            "filters": {
              "all_of": [
                {
                  "test": "weather_at_position",
                  "value": "clear"
                },
                {
                  "test": "has_tag",
                  "operator": "!=",
                  "value": "state_clear"
                }
              ]
            },
            "event": "addon:set_clear"
          },
          {
            "filters": {
              "all_of": [
                {
                  "test": "weather_at_position",
                  "value": "rain"
                },
                {
                  "test": "has_tag",
                  "operator": "!=",
                  "value": "state_rain"
                }
              ]
            },
            "event": "addon:set_rain"
          },
          {
            "filters": {
              "all_of": [
                {
                  "test": "weather_at_position",
                  "value": "thunder"
                },
                {
                  "test": "has_tag",
                  "operator": "!=",
                  "value": "state_thunder"
                }
              ]
            },
            "event": "addon:set_thunder"
          }
        ]
      }
    },
    "events": {
      "addon:set_clear": {
        "run_command": {
          "command": [
            "tag @s remove state_rain",
            "tag @s remove state_thunder",
            "tag @s add state_clear",
            "scoreboard players set global weather_state 0"
          ]
        }
      },
      "addon:set_rain": {
        "run_command": {
          "command": [
            "tag @s remove state_clear",
            "tag @s remove state_thunder",
            "tag @s add state_rain",
            "scoreboard players set global weather_state 1"
          ]
        }
      },
      "addon:set_thunder": {
        "run_command": {
          "command": [
            "tag @s remove state_clear",
            "tag @s remove state_rain",
            "tag @s add state_thunder",
            "scoreboard players set global weather_state 2"
          ]
        }
      }
    }
  }
}

Running Commands from Scoreboard and Tag States

Once your player entity or `addon:weather_watcher` entity is applying tags and updating the scoreboard, your `.mcfunction` files can react to the weather using standard `/execute` syntax. This keeps your complex command logic out of the entity JSON file—which is harder to debug and requires a world reload when edited—and inside function files that you can reload on the fly with `/reload`.

For player-specific effects, target `@a[tag=in_rain]`. Because the tag is managed by the `is_in_water_or_rain` and `is_in_water` filter combination, any player who walks under an overhang or dives into an ocean immediately loses the `in_rain` tag on the very next tick. For world-wide mechanics, check the fake player score `global` on the `weather_state` objective.

Make sure you initialize the `weather_state` scoreboard objective and summon your watcher entity inside a loaded `/tickingarea` during your pack setup function. If the chunk containing the `addon:weather_watcher` entity unloads, its `minecraft:environment_sensor` stops ticking and your global score will freeze in whatever state it held last.

BP/functions/weather/tick_check.mcfunction
# Give players standing directly in the rain a slow regeneration effect
ffect @a[tag=in_rain] regeneration 2 0 true

# Run a world event only during a thunderstorm (weather_state = 2)
execute if score global weather_state matches 2 as @a at @s run playsound ambient.weather.thunder @s ~ ~ ~ 0.2 1.0

# Extinguish custom campfires across loaded areas when it rains or thunders (weather_state >= 1)
execute if score global weather_state matches 1.. as @e[type=addon:campfire_marker] at @s if block ~ ~ ~ minecraft:campfire["extinguished"=false] run setblock ~ ~ ~ minecraft:campfire["extinguished"=true]

Method 2: Pure Command Block Physical Detector

If you are building a command recipe for a world where you cannot modify `player.json` or add custom entities, you can detect rain by exploiting how the Overworld interacts with fire or cauldrons. Rain naturally extinguishes fire on top of standard blocks, and it slowly fills open cauldrons. Neither mechanic is instant—both rely on random ticks or internal weather intervals—so this method has a slight delay compared to an entity sensor.

The fastest physical detector uses a flame-enchanted bow dispenser or `/setblock` loop that maintains a `minecraft:fire` block on top of `minecraft:netherrack` exposed to the sky, or a Bee / Strider / Snow Golem health check. However, since `minecraft:netherrack` keeps fire burning forever even during rain, you must place the fire on a non-flammable block with a `/setblock` command or test an entity that reacts to water contact, such as a `minecraft:blaze` or `minecraft:snow_golem`.

A cleaner, silent command-only trick is to summon an invulnerable or constantly healed `minecraft:strider` or `minecraft:enderman` in a bedrock box open to the sky, or to use a daylight detector comparison. Better yet, you can use `/execute` to test a `minecraft:cauldron` that you reset to empty as soon as it fills by one level, though cauldron filling is quite slow. For near-instant vanilla command detection without modifying `player.json`, place a `minecraft:campfire` exposed to the sky in a ticking area— Wait: rain does not extinguish vanilla campfires in Bedrock. Instead, use a `minecraft:cauldron` for slow detection, or test a vanilla mob whose behavior changes in rain. In practice, even a minimal behavior pack with a single `environment_sensor` entity is far more reliable than any block-based workaround.

Method 3: Script API Weather Events

If your add-on already uses a script module (`@minecraft/server`), you do not need entity sensors or ticking functions at all. The Script API provides a native `weatherChange` after-event on `world.afterEvents`, as well as a way to query or change the weather on a dimension object. Using the event listener is completely passive and consumes zero tick performance while the weather is steady.

When the `weatherChange` event fires, its event data gives you the new weather state and the dimension where the change happened. From inside the callback, you can call `dimension.runCommand()` to execute your `.mcfunction` file or update a scoreboard objective, combining the convenience of commands with the accuracy of scripts.

BP/scripts/main.js
import { world } from "@minecraft/server";

world.afterEvents.weatherChange.subscribe((eventData) => {
  const overworld = world.getDimension("overworld");
  const currentWeather = eventData.newWeather;

  if (currentWeather === "Rain") {
    overworld.runCommand("scoreboard players set global weather_state 1");
    overworld.runCommand("function weather/on_rain_start");
  } else if (currentWeather === "Thunder") {
    overworld.runCommand("scoreboard players set global weather_state 2");
    overworld.runCommand("function weather/on_thunder_start");
  } else {
    overworld.runCommand("scoreboard players set global weather_state 0");
    overworld.runCommand("function weather/on_weather_clear");
  }
});

Which versions this applies to

Applies to Minecraft Bedrock 1.19.50 and newer. The entity `run_command` event response requires `format_version` 1.19.0 or higher (replacing the older `queue_command` syntax in newer entity formats) and does not require any experimental toggles. The `@minecraft/server` `weatherChange` event is available in stable Script API releases.

When it does not work

What you seeWhyThe fix
The `on_rain_start` function runs 20 times every second as long as it is raining, flooding the chat log and lagging the world.`minecraft:environment_sensor` evaluates its filters on every single tick. If the filter remains true after the event fires, the sensor fires the event again on the very next tick.Add a `has_tag` filter with `"operator": "!="` to your sensor trigger, and add that tag inside the event's `run_command` block. Use a second trigger with the opposite filter to remove the tag when the rain stops.
Content Log Error: `[Entities][error]-addon:weather_watcher |addon:set_rain | run_command: failed to parse command` or commands inside the entity event silently do nothing.You used an older entity `format_version` that expects `queue_command` instead of `run_command`, or you included a leading forward slash (`/`) at the start of a command string inside the `command` array.Ensure the entity file uses a modern `format_version` such as `1.20.40` when using `run_command`, and remove any leading `/` from the command strings.
The `weather_watcher` entity never updates the `weather_state` score even when rain is visibly falling around the player.The watcher entity was summoned in a desert, savanna, or roofed spot where `weather_at_position` always reports `clear`, or the chunk containing the watcher entity was unloaded because the player walked away.Summon the `addon:weather_watcher` high in the sky inside a biome where rain can fall (such as Plains), and register that chunk with `/tickingarea add circle ~ ~ ~ 2 weather_check`.
Players trigger the rain detector whenever they swim in an ocean or step into a puddle.The filter `is_in_water_or_rain` returns `true` for both submerged entities and entities touched by falling rain.Wrap your filter in an `all_of` array and pair `is_in_water_or_rain` (`true`) with `is_in_water` (`false`) so that standing in water blocks cancels the trigger.

Reference, straight from the game files

Read out of the game itself, so the ids match the version you are building for.