Action Framework Performance Optimization
The core automation framework (actions, triggers, and conditions) has been optimized to use const references instead of pass-by-value for parameter passing. This reduces memory allocations by 83% in the automation execution path.
This is a breaking change for external components with custom actions or conditions in ESPHome 2025.11.0 and later.
What needs to change
Section titled “What needs to change”External components must update their action/condition method signatures to use const references:
// ❌ Beforetemplate<typename... Ts>class MyAction : public Action<Ts...> { void play(Ts... x) override { // ... }};
// ✅ Aftertemplate<typename... Ts>class MyAction : public Action<Ts...> { void play(const Ts&... x) override { // ← Add const& // ... (no other changes needed) }};All signatures to update
Section titled “All signatures to update”void play(Ts... x)→void play(const Ts&... x)void play_complex(Ts... x)→void play_complex(const Ts&... x)bool check(Ts... x)→bool check(const Ts&... x)
Compilation errors
Section titled “Compilation errors”External components will fail to compile with clear error messages pointing to the methods that need updating:
error: no declaration matches 'void MyAction::play(Ts ...)'note: candidate is: 'void MyAction::play(const Ts& ...)'Finding code that needs updates
Section titled “Finding code that needs updates”# Find actions/conditions that need updatinggrep -rn "void play(Ts\.\.\. \w\+) override" your_component/grep -rn "void play_complex(Ts\.\.\. \w\+) override" your_component/grep -rn "bool check(Ts\.\.\. \w\+) override" your_component/Supporting multiple ESPHome versions
Section titled “Supporting multiple ESPHome versions”If your external component needs to support both old and new ESPHome versions, you can ifdef just the signature:
// Use version guards for just the signature#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0) void play(const Ts&... x) override#else void play(Ts... x) override#endif { // Implementation (no duplication needed) }Why this change
Section titled “Why this change”Previously, the automation framework made 6 copies of every argument as it passed through the call chain. For std::string arguments (like logger messages), this meant 6 heap allocations per trigger event.
The change eliminates these copies, resulting in 83% fewer heap allocations at runtime.
No logic changes required
Section titled “No logic changes required”This is a purely mechanical change - you only need to update method signatures. Your implementation logic does not need to change.
Reference Pull Request
Section titled “Reference Pull Request”Questions?
Section titled “Questions?”If you have questions about migrating your external component, please ask in:
- ESPHome Discord - #devs channel
- ESPHome GitHub Discussions
Copyright © 2026 ESPHome - A project from the Open Home Foundation
Comments
Feel free to leave a comment here to discuss this post with others. You can ask questions, share your experience, or suggest improvements. If you have a question about a specific feature or issue, please consider using the ESPHome Discord. Stick to English and follow ESPHome's code of conduct. These comments exist on a discussion on GitHub, so you can also comment there directly if you prefer.