You have nine motion-sensor lights. You wrote the first automation, copied it eight times, and swapped the entity IDs. Then you decided the lights should wait 2 minutes instead of 1, and you got to edit nine files. At 2 AM, with one of them still wrong.
A blueprint fixes this. It is an automation (or script) with the changeable parts cut out and replaced by named inputs. You write the logic once, then create as many automations from it as you want, each with its own sensor and light. Fix a bug in the blueprint and every automation built from it gets the fix.
Full example: Clone the example files at github.com/KingPin/sumguy-examples/home-automation/home-assistant-blueprints
Copy-paste is the problem
Here is what the nine-copy approach looks like. Same trigger, same actions, one entity ID different:
- alias: Hallway motion light triggers: - trigger: state entity_id: binary_sensor.hallway_motion to: "on" actions: - action: light.turn_on target: entity_id: light.hallway - delay: 120 - action: light.turn_off target: entity_id: light.hallwayCopy that for the kitchen, the garage, the porch. Now find the bug where the light turns off while you are still in the room. You fix it eight times and miss one. A blueprint turns those nine copies into nine short instances of one definition.
This post uses the current YAML syntax from Home Assistant 2024.10 onward: triggers:, conditions:, and actions: are plural, and each trigger starts with - trigger: state (it used to be platform:). The latest release at the time of writing is 2026.11.0. Everything below follows the official docs for that version.
Import a community blueprint
Before you write anything, import one. Go to Settings > Automations & scenes > Blueprints, select Import blueprint, paste an address, and select Preview, then Import blueprint. Home Assistant imports from the community forum, GitHub, GitHub gists, and the Home Assistant website. For other addresses it asks you to continue only if you trust the source. A blueprint can run actions on your house, so treat an import like running a script from the internet.
Many blueprint pages also have an Import blueprint button. That button is a My Home Assistant link. You can build your own for any blueprint file:
https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=<URL-OF-THE-YAML-FILE>It opens the import dialog on your instance with the address pre-filled.
Imported blueprints land on disk like this:
config/blueprints/automation/<author>/<name>.yamlconfig/blueprints/script/<author>/<name>.yamlThe folder name comes from the source. For GitHub it is the user, and the file keeps its name. You can create your own subfolders, and you can skip the UI import and drop a file in by hand. Reload automations (or scripts) and it shows up.
Anatomy of a blueprint
A blueprint is a normal automation with a blueprint: header on top. Only name and domain are required. Here is the header from the motion light we build in this post:
blueprint: name: Motion Light (SumGuy) description: > Turn lights on when motion is detected, keep them on for a while after the last motion, then turn them off. Optionally only when it is dark. domain: automation author: SumGuy source_url: https://github.com/KingPin/sumguy-examples/blob/main/home-automation/home-assistant-blueprints/blueprints/automation/sumguy/motion_light.yaml homeassistant: min_version: 2024.10.0 input: motion_sensor: name: Motion sensor selector: entity: filter: - domain: binary_sensor device_class: motion - domain: binary_sensor device_class: occupancyThe keys:
nameanddomainare required.domainisautomation,script, ortemplate.descriptionis optional but worth writing. It accepts Markdown.authoris just a label.source_urlis what makes Re-import work later.homeassistant: min_versiontakesmajor.minor.patch, and all three parts are required. Set it whenever you use a recent feature, so older installs fail with a clear message instead of a confusing one.inputis the map of things the user fills in.
Inputs and selectors
Each input can have a name, description, default, and a selector. The selector controls the form widget. Without one, the user gets a bare text box and has to guess what goes in it. That is how you end up with a bug report from yourself.
The selectors used in this post:
lights: name: Lights selector: target: entity: domain: light no_motion_wait: name: Wait time default: 120 selector: number: min: 0 max: 3600 unit_of_measurement: seconds only_when_dark: name: Only when dark default: false selector: boolean: active_after: name: Active after default: "00:00:00" selector: time: alert_actions: name: Alert actions default: [] selector: action:entitywith afilterofdomainanddevice_classlimits the picker to, say, motion sensors. A list of filters means “matches any of these”.targetlets the user pick entities, devices, or areas. Pass it whole to an action’starget:.numbergives a slider (or a box withmode: box). The value is a number.booleanis a toggle.timereturns a 24-hour time such as23:59:59.actionshows the full automation action editor, and the value is a list of actions. This is how a blueprint lets users bring their own notification.
alert_actions comes from the door alert blueprint later in this post. In the motion light, the boolean and time inputs sit inside a collapsible Extras section, shown further down.
Using inputs with !input
Anywhere outside the blueprint: header, !input name is replaced with whatever the user chose (or the default). It works for whole objects too, not just strings:
triggers: - trigger: state entity_id: !input motion_sensor from: "off" to: "on"
actions: - alias: Turn on the light action: light.turn_on target: !input lights - alias: Wait for motion to stop wait_for_trigger: - trigger: state entity_id: !input motion_sensor from: "on" to: "off" - delay: seconds: !input no_motion_wait - action: light.turn_off target: !input lightsPair it with mode: restart so a new motion event resets the timer. That is the same shape as the built-in Motion-activated Light blueprint that ships with Home Assistant.
The template gotcha
You cannot write !input inside a Jinja template. The docs are direct about it: inputs are custom YAML tags, not template variables. This fails:
# Broken: !input is not available inside {{ }}brightness_pct: "{{ !input brightness }}"Assign the input to a variable first, then use the variable:
variables: brightness: !input brightness only_when_dark: !input only_when_dark lux_sensor: !input lux_sensor dark_below: !input dark_below
conditions: - condition: template value_template: > {{ not only_when_dark or lux_sensor == '' or states(lux_sensor) | float(0) < dark_below | float(0) }}
actions: - action: light.turn_on target: !input lights data: brightness_pct: "{{ brightness }}"The variables: block makes each input a real template variable. Script blueprints do the same thing with a script-level variables: block.
trigger_variables for triggers
variables: only exists once a run has started, so triggers cannot see it. For templates inside triggers, such as a trigger’s enabled option, use trigger_variables:. Home Assistant evaluates these when it sets up the triggers (when the automation loads or turns on), and only limited templates work there. A plain !input assignment is fine:
trigger_variables: repeat_reminder: !input repeat_reminder
triggers: - trigger: state entity_id: !input door_sensor to: "on" for: minutes: !input open_minutes - trigger: time_pattern minutes: "/30" enabled: "{{ repeat_reminder }}"The second trigger exists only when the user flips the repeat toggle. If the input is a lone boolean and you do not need a template, skip all this and write enabled: !input repeat_reminder directly. The time_pattern reminder is clock-aligned: it fires at :00 and :30 of each hour, not 30 minutes after the first alert.
The same blueprint ends with actions: !input alert_actions. The user builds the notification in the normal action editor, and the blueprint runs it. One blueprint, any alert.
Collapsible input sections
A blueprint with twelve inputs is a wall of form fields. Release 2024.6 added input sections: group inputs under a key that has its own input: map, and optionally collapse it.
extras: name: Extras icon: mdi:tune description: Optional tweaks. Safe to leave alone. collapsed: true input: brightness: name: Brightness default: 100 selector: number: min: 1 max: 100 unit_of_measurement: "%" only_when_dark: name: Only when dark default: false selector: boolean:Three rules. Sections are display only: input names must stay unique across the whole blueprint, and !input brightness ignores the section. Every input in a collapsed section needs a default, or the user cannot leave it hidden. And set min_version to at least 2024.6.0, or older versions throw errors.
Create automations from it
In the UI, open the blueprint and select Create automation. Fill in the form, save. In YAML, you point at the file by its path under blueprints/automation/:
- alias: Hallway motion light use_blueprint: path: sumguy/motion_light.yaml input: motion_sensor: binary_sensor.hallway_motion lights: entity_id: light.hallway no_motion_wait: 60
- alias: Kitchen motion light use_blueprint: path: sumguy/motion_light.yaml input: motion_sensor: binary_sensor.kitchen_motion lights: area_id: kitchen no_motion_wait: 300 only_when_dark: true lux_sensor: sensor.kitchen_lux dark_below: 30Each instance is under a dozen lines. Nine rooms are nine small blocks, and the logic lives in one file.
Test with one instance first. Create the hallway automation, walk past the sensor, then open the automation and check its Traces tab. The trace shows which trigger fired, whether the template condition passed, and what each action did. If the dark-only condition blocks you, the trace says so, and you fix the blueprint once instead of nine times. Only then add the other rooms.
Script blueprints
Script blueprints arrived in release 2023.7. The shape is the same, with domain: script and a sequence: instead of triggers:/actions:. Scripts have no triggers, so they are good for reusable things you call from automations, dashboards, or voice.
blueprint: name: Fade Lights Off (SumGuy) description: Dim lights in steps, then turn them off. Good for bedtime. domain: script homeassistant: min_version: 2024.10.0 input: lights: name: Lights selector: target: entity: domain: light steps: name: Number of steps default: 5 selector: number: min: 2 max: 30 step_seconds: name: Seconds per step default: 60 selector: number: min: 1 max: 600 unit_of_measurement: seconds
mode: restart
variables: steps: !input steps
sequence: - repeat: count: !input steps sequence: - action: light.turn_on target: !input lights data: brightness_pct: > {{ [ (100 * (steps - repeat.index) / steps) | round(0), 1 ] | max }} - delay: seconds: !input step_seconds - action: light.turn_off target: !input lightsInstances go in scripts.yaml with the same use_blueprint: block, or you create them from the Blueprints page.
bedtime_fade: alias: Bedtime fade use_blueprint: path: sumguy/fade_lights_off.yaml input: lights: entity_id: light.bedroom steps: 10 step_seconds: 30The practical split: automation blueprints answer “when does this run”, script blueprints answer “what does this do”. If you want one behavior called from five places, write a script blueprint. If you want one trigger pattern repeated across rooms, write an automation blueprint. Combine them by letting an automation blueprint take an action input that calls your script.
Updating, and the gotcha that eats your edits
When the author publishes a fix, open the Blueprints page, use the three dots menu on the blueprint, and select Re-import blueprint. This works only if the blueprint has a source_url, which imported blueprints and the built-in ones have. A file you wrote by hand without one shows “Unable to re-import blueprint: no source URL”.
Re-import overwrites the file. If you edited the YAML on disk to tweak it, your edits are gone. The docs also warn that an incompatible new version can break your automations, because renamed or removed inputs leave instances pointing at nothing. Before you re-import anything you depend on, copy the old file somewhere.
Changes take effect after a reload. Edit a blueprint file by hand, reload automations, and every automation built from it picks up the new logic. Home Assistant does not need a restart. This is the payoff and the risk in one: one edit changes nine automations at once.
Take control when a blueprint is too tight
Say the kitchen light needs one odd extra condition that the blueprint has no input for. Since release 2024.7 you can open that automation, use the three dots menu, and select Take control. Home Assistant shows a preview of the plain automation, and after you select Yes and save, that automation is a regular one you can edit freely.
The gotchas: it is one way. You cannot convert it back. The blueprint itself does not change, and the other automations keep using it. And it is unavailable for automations that are not stored in automations.yaml or have no ID.
Take control is a fine escape hatch for one weird room. If you find yourself taking control of every third instance, the blueprint is missing an input, so add it.
When not to use a blueprint
A blueprint is a forklift: great when you move the same pallet nine times, silly for one couch. My rules:
- Use one when you would otherwise copy an automation three or more times. Three is where the second edit starts to hurt.
- Skip it for one-off automations. “Turn on the porch light at sunset” is eight lines. A blueprint adds a header, inputs, a file, and a reload step for something that exists once.
- Skip it when the instances differ in logic, not just in values. If every room needs different conditions and different action orders, you are bolting
choose:blocks into a blueprint to fake what separate automations do cleanly. - Be careful with community blueprints you cannot read. Open the YAML before you import. It is short.
If you are unsure, write the plain automation first. Convert it when the second copy shows up. The tutorial in the Home Assistant docs does exactly this: take a working automation, replace the values with !input, add the blueprint: header.
Common Questions
Can I edit a Home Assistant blueprint after importing it?
Yes. Imported blueprints are plain YAML files under config/blueprints/, so you can edit them directly and reload automations to apply the change to every automation using that blueprint. The catch is that Re-import blueprint overwrites your edits. Keep a copy of the file before you re-import.
Do I need to restart Home Assistant after changing a blueprint?
No. Reloading automations is enough. After you edit a blueprint file, reload automations (or scripts, for a script blueprint) and every automation built from it uses the new version. A full restart is unnecessary, and you do not have to edit the individual automations.
Can I convert a blueprint automation back into a normal automation?
Yes, with Take control, available since Home Assistant 2024.7. Open the automation, choose Take control from the three dots menu, then confirm and save. The result is a regular automation. The conversion is permanent, and the original blueprint and its other automations stay unchanged.
What Home Assistant version do I need for blueprints with sections or script blueprints?
Script blueprints need 2023.7 or newer, and collapsible input sections need 2024.6 or newer. The plural triggers: and actions: syntax used in this post needs 2024.10 or newer. Set homeassistant: min_version in the blueprint header so older installs reject it with a clear message.