RingBuffer Moved Out of Core Into ring_buffer Helper Component
RingBuffer has moved from esphome/core/ring_buffer.h into a new ring_buffer helper component at esphome/components/ring_buffer/ring_buffer.h under the esphome::ring_buffer namespace. The old location is deprecated and will be removed in ESPHome 2026.11.0.
This is a breaking change for external components in ESPHome 2026.5.0 and later.
Background
PR #16298: Move core ring buffer to helper component
The core RingBuffer was an ESP32-only implementation used exclusively by audio components — audio, i2s_audio, micro_wake_word, mixer, resampler, sound_level, speaker, voice_assistant. Nothing outside that audio cluster touches it. Living in esphome/core/ meant:
- The
ring_buffer.hheader was parsed for every build, regardless of platform or whether audio was in use. Linker stripping kept unused code out of the final binary, but build-time parsing and tooling overhead applied universally. - Changes to
RingBuffercouldn't be staged in anexternal_componentsPR — they always required a core change. - The ESP32-only implementation lived alongside genuinely cross-platform core code.
Moving it into a real component (esphome::ring_buffer::RingBuffer) lets audio consumers AUTO_LOAD it the same way every other shared utility is pulled in, and opens the door to iterating on the implementation without touching core.
The old esphome/core/ring_buffer.h header now forwards to the new location and will be removed in 2026.11.0 per the standard 6-month policy. The behavior of the shim depends on whether your component declares AUTO_LOAD = ["ring_buffer"]:
- With
AUTO_LOAD: the shim forwardsesphome::RingBuffertoesphome::ring_buffer::RingBuffervia ausingalias markedESPDEPRECATED(...). Code keeps compiling, but each use emits a deprecation warning at the call site. - Without
AUTO_LOAD: the new header isn't on the include path, so the shim fires a hard#errortelling you exactly what to do: "esphome/components/ring_buffer/ring_buffer.hnot found. Add 'ring_buffer' to your component's AUTO_LOAD list to use esphome::ring_buffer::RingBuffer." The build fails immediately rather than producing a confusing missing-header diagnostic from somewhere else.
What's Changing
C++ include and namespace
// Before
#include "esphome/core/ring_buffer.h"
std::unique_ptr<esphome::RingBuffer> buf = esphome::RingBuffer::create(1024);
// After
#include "esphome/components/ring_buffer/ring_buffer.h"
std::unique_ptr<esphome::ring_buffer::RingBuffer> buf =
esphome::ring_buffer::RingBuffer::create(1024);
Python codegen — declare AUTO_LOAD
Any component whose C++ uses RingBuffer must auto-load the helper component so the build system pulls in its sources. In your component's __init__.py:
AUTO_LOAD = ["ring_buffer"]
If your component already has an AUTO_LOAD, append "ring_buffer" to it.
Who This Affects
External audio / streaming components that use RingBuffer directly — typically:
- Custom microphone / I²S audio pipelines
- Speaker / playback components
- Streaming protocol bridges (BLE audio, Nordic UART, etc.)
- Forks or extensions of
micro_wake_word,voice_assistant,speaker
All in-tree consumers (audio, i2s_audio, micro_wake_word, mixer, resampler, sound_level, speaker, voice_assistant) were migrated in esphome/esphome#16298.
Non-audio components are unaffected.
Migration Guide
-
Update the include path:
-#include "esphome/core/ring_buffer.h" +#include "esphome/components/ring_buffer/ring_buffer.h" -
Update the namespace at every callsite:
-esphome::RingBuffer::create(size); +esphome::ring_buffer::RingBuffer::create(size);If you have many callsites, you can avoid editing each one by adding a
using esphome::ring_buffer::RingBuffer;declaration inside your component's own namespace block soRingBufferresolves correctly from unqualified references:namespace esphome::my_component { using esphome::ring_buffer::RingBuffer; // ← here, not at file scope class MyComponent : public Component { std::unique_ptr<RingBuffer> buf_; // unqualified still works }; } // namespace esphome::my_componentAvoid putting the
usingat file scope (outside any namespace) — that pulls the name into the global namespace, which works for::RingBufferlookups but doesn't help code insideesphome::my_componentthat previously relied onesphome::RingBufferbeing a sibling. -
Add
AUTO_LOADin your component's__init__.py:AUTO_LOAD = ["ring_buffer"]
The API of RingBuffer itself (create(), read(), write(), write_without_replacement(), available(), etc.) is unchanged — only its location and namespace move.
Timeline
- 2026.5.0: New location active; old
esphome/core/ring_buffer.hdeprecated (compile warning). - 2026.11.0: Old header removed.
Finding Code That Needs Updates
# C++ — find the old include
grep -rn 'esphome/core/ring_buffer.h' your_component/
# C++ — find old namespace usage
grep -rn 'esphome::RingBuffer' your_component/
# Python — find AUTO_LOAD declarations that need ring_buffer added
grep -rn 'AUTO_LOAD' your_component/
Questions?
If you have questions about migrating your external component, please ask in:
- ESPHome Discord - #devs channel
- ESPHome GitHub Discussions
Related Documentation
- PR #16298 — Move core ring buffer to helper component
Comments
Feel free to leave a comment here to discuss this post wth 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.