MQTT Discovery Base Topic at Device Level

Hi all,

Is it possible to have an MQTT discovery Base Topic apply to an entire device, rather than having to define it for each individual component in the device discovery payload?

I’m using MQTT device discovery for a custom device with multiple components. As the root of the command and status topics of all components will be the same, it would be preferable to use a single base topic for all (to minimise discovery payload size), but to date I can only get this to work when I define the base topic at component level.

The documentation doesn’t seem to explicitly indicate where to define the base topic, though all examples of its usage show it used for single component discovery only.

A base topic ~ may be defined in the payload to conserve memory when the same topic base is used multiple times. In the value of configuration variables ending with _topic , ~ will be replaced with the base topic, if the ~ occurs at the beginning or end of the value.

The following sample discovery message payload, with base topics declared at component level, works fine. However, when multiple components are added it creates a lot of duplication of the base topic.

{
   "dev":{
      "ids":"testDevice1",
      "name":"testDevice1"
   },
   "o":{
      "name":"bla2mqtt",
      "sw":"2.1",
      "url":"https://bla2mqtt.example.com/support"
   },
   "cmps":{
      "enable":{
         "p":"switch",
         "~":"house/device1",
         "cmd_t":"~/enable/cmd",
         "stat_t":"~/enable/status",
         "name":"Enable",
         "uniq_id":"enable1"
      },
      "alarm":{
         "p":"switch",
         "~":"house/device1",
         "cmd_t":"~/alarm/cmd",
         "stat_t":"~/alarm/status",
         "name":"Alarm",
         "uniq_id":"alarm1"
      }
   }
}

I have tried to move the base topic to the top level, or to “dev”, without success, the device isn’t discovered by the MQTT integration in these cases.
For example, the following discovery payload is not successfully processed:

{
   "dev":{
      "ids":"testDevice1",
      "name":"testDevice1"
   },
   "o":{
      "name":"bla2mqtt",
      "sw":"2.1",
      "url":"https://bla2mqtt.example.com/support"
   },
   "~":"house/device1",
   "cmps":{
      "enable":{
         "p":"switch",
         "cmd_t":"~/enable/cmd",
         "stat_t":"~/enable/status",
         "name":"Enable",
         "uniq_id":"enable1"
      },
      "alarm":{
         "p":"switch",
         "cmd_t":"~/alarm/cmd",
         "stat_t":"~/alarm/status",
         "name":"Alarm",
         "uniq_id":"alarm1"
      }
   }
}

I also have not been able to find queries or feature requests for this in the community - possibly indicating that it works fine for others, or perhaps I’m trying to go about this in the wrong way.

I’m running Home Assistant 2025.3.4 using the HassOS image.

Based on the three examples shown in the documentation, my understanding is that ~ is the name of a dictionary key. This key can be referenced by the values of other keys in the same dictionary.

That explains why the following example fails to work because ~ is not a key in the enable and alarm dictionaries.

{
   "dev":{
      "ids":"testDevice1",
      "name":"testDevice1"
   },
   "o":{
      "name":"bla2mqtt",
      "sw":"2.1",
      "url":"https://bla2mqtt.example.com/support"
   },
   "~":"house/device1",
   "cmps":{
      "enable":{
         "p":"switch",
         "cmd_t":"~/enable/cmd",
         "stat_t":"~/enable/status",
         "name":"Enable",
         "uniq_id":"enable1"
      },
      "alarm":{
         "p":"switch",
         "cmd_t":"~/alarm/cmd",
         "stat_t":"~/alarm/status",
         "name":"Alarm",
         "uniq_id":"alarm1"
      }
   }
}

Thanks for the input!

I guess this makes sense, though it would be nice if a base topic could be shared for all components when using device discovery; this seems like a very normal use-case. I wonder if the current implementation is a hold-over from when component discovery was the only option?

If there really is no way to do this at present, perhaps it warrants a feature request? It doesn’t seem like the most difficult feature to implement - pass the ~ key-value pair to all component dictionaries - but the lack of queries on the forum might indicate it wouldn’t be high on the priority list!
In any case, it’s more of a nice to have to save some memory, it works fine when base topic is used at component level.