SSR-safe MQTT integration for Nuxt 3 using mqtt.js, with runtime config support and a simple composable API.
- SSR-safe — the MQTT client only runs on the client side, so your app renders correctly on the server
- One global connection — a single MQTT client is shared across your entire app via a Nuxt plugin
- Simple composable API —
useMQTT()gives youpublish()andsubscribe()out of the box - Runtime config support — configure the broker URL and options via
nuxt.config.tsor environment variables - Auto-imported —
useMQTT()is auto-imported, no manual imports needed - Ideal for IoT — works great with ESP32, Raspberry Pi, smart home dashboards, and any MQTT-based project
# pnpm
pnpm add nuxt-mqtt
# npm
npm install nuxt-mqtt
# yarn
yarn add nuxt-mqtt// nuxt.config.ts
export default defineNuxtConfig({
modules: ['nuxt-mqtt'],
mqtt: {
url: 'ws://localhost:9001', // Required — your MQTT broker WebSocket URL
},
})Important: The
urlmust be a WebSocket URL (ws://orwss://), because the MQTT client runs in the browser. Standard MQTT ports (e.g.mqtt://localhost:1883) will not work in the browser.
<template>
<div>
<p>Temperature: {{ temperature }}°C</p>
<button @click="toggleLight">Toggle Light</button>
</div>
</template>
<script setup lang="ts">
const temperature = ref('--')
const { publish, subscribe } = useMQTT()
// Subscribe to a topic — the callback fires every time a message arrives
subscribe('home/livingroom/temp', (msg) => {
temperature.value = msg
})
// Publish a message (string or object)
function toggleLight() {
publish('home/livingroom/light/set', { state: 'toggle' })
}
</script>That's it! No imports needed — useMQTT() is auto-imported by the module.
Returns an object with two methods:
Sends a message to the given MQTT topic.
| Parameter | Type | Description |
|---|---|---|
topic |
string |
The MQTT topic to publish to (e.g. 'home/light/set') |
message |
string | object |
The payload. Objects are automatically serialized to JSON |
const { publish } = useMQTT()
// Send a string
publish('home/light/set', 'on')
// Send an object (auto-serialized to JSON)
publish('home/blinds/set', { position: 50 })Subscribes to an MQTT topic and calls the callback whenever a message is received. Returns an unsubscribe function that you should call to clean up when the component is unmounted.
| Parameter | Type | Description |
|---|---|---|
topic |
string |
The MQTT topic to subscribe to |
callback |
(message: string) => void |
Called with the message payload as a string |
Returns: () => void — a cleanup function that removes the listener
const { subscribe } = useMQTT()
// Basic usage
subscribe('home/livingroom/temp', (msg) => {
console.log('Temperature:', msg)
})
// With cleanup (recommended)
const unsubscribe = subscribe('home/livingroom/temp', (msg) => {
console.log('Temperature:', msg)
})
onUnmounted(() => {
unsubscribe()
})All configuration goes under the mqtt key in nuxt.config.ts. The module accepts all mqtt.js client options plus the required url field.
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['nuxt-mqtt'],
mqtt: {
// Required
url: 'ws://localhost:9001',
// Optional — all mqtt.js options are supported
clientId: 'my_nuxt_app', // defaults to 'nuxt_' + random hex
clean: true, // default: true
connectTimeout: 4000, // default: 4000 (ms)
reconnectPeriod: 1000, // default: 1000 (ms)
// Authentication (if your broker requires it)
username: 'my_user',
password: 'my_password',
},
})You can use environment variables to avoid hardcoding credentials. Since the module uses runtimeConfig.public.mqtt, you can override values with NUXT_PUBLIC_MQTT_* env vars:
NUXT_PUBLIC_MQTT_URL=wss://broker.example.com:8084
NUXT_PUBLIC_MQTT_USERNAME=my_user
NUXT_PUBLIC_MQTT_PASSWORD=my_passwordNote: Since the MQTT configuration is under
runtimeConfig.public, it is exposed to the browser. Do not put secrets here unless you are using a private/internal network. For private brokers requiring secure credentials, consider proxying through your server.
| Option | Type | Default | Description |
|---|---|---|---|
url |
string |
— | Required. WebSocket URL of your MQTT broker |
clientId |
string |
'nuxt_' + random |
Unique client identifier |
clean |
boolean |
true |
Start a clean session on connect |
connectTimeout |
number |
4000 |
Connection timeout in milliseconds |
reconnectPeriod |
number |
1000 |
Reconnection interval in milliseconds |
username |
string |
— | Broker username |
password |
string |
— | Broker password |
For the full list of options, see the mqtt.js documentation.
<template>
<div>
<h2>Living Room</h2>
<p>Temperature: {{ temperature }}°C</p>
<p>Humidity: {{ humidity }}%</p>
<p>Light: {{ lightState }}</p>
<button @click="toggleLight">Toggle Light</button>
<h2>Blinds</h2>
<input type="range" min="0" max="100" v-model="blindsPosition" @change="setBlinds" />
<p>Position: {{ blindsPosition }}%</p>
</div>
</template>
<script setup lang="ts">
const temperature = ref('--')
const humidity = ref('--')
const lightState = ref('off')
const blindsPosition = ref(0)
const { publish, subscribe } = useMQTT()
// Subscribe to multiple topics
subscribe('home/livingroom/temp', (msg) => {
temperature.value = msg
})
subscribe('home/livingroom/humidity', (msg) => {
humidity.value = msg
})
subscribe('home/livingroom/light/state', (msg) => {
lightState.value = msg
})
subscribe('home/livingroom/blinds/state', (msg) => {
blindsPosition.value = Number(msg)
})
// Publish commands
function toggleLight() {
const newState = lightState.value === 'on' ? 'off' : 'on'
publish('home/livingroom/light/set', newState)
}
function setBlinds() {
publish('home/livingroom/blinds/set', { position: blindsPosition.value })
}
</script>If you don't have an MQTT broker yet, the easiest way to get started is with Mosquitto:
docker run -it -p 1883:1883 -p 9001:9001 eclipse-mosquittoYou may need a mosquitto.conf that enables the WebSocket listener:
listener 1883
listener 9001
protocol websockets
allow_anonymous true
docker run -it -p 1883:1883 -p 9001:9001 \
-v $(pwd)/mosquitto.conf:/mosquitto/config/mosquitto.conf \
eclipse-mosquittobrew install mosquitto
# Edit /opt/homebrew/etc/mosquitto/mosquitto.conf to add WebSocket listener
# Then start with:
brew services start mosquittoFor quick testing without setting up your own broker:
mqtt: {
url: 'wss://test.mosquitto.org:8081',
}Warning: Public brokers are shared — do not send sensitive data.
- Module setup — when Nuxt builds your app, the module reads the
mqttconfig and stores it inruntimeConfig.public.mqtt - Client plugin — on the client side only (
.client.tsplugin), an MQTT connection is established usingmqtt.connect()and provided globally as$mqttvia Nuxt's plugin system - Composable —
useMQTT()accesses the$mqttclient from the Nuxt app context and wraps it with convenientpublish()andsubscribe()methods - SSR-safe — on the server, the plugin doesn't run, so there is no MQTT connection during SSR. The composable should only be called in client-side lifecycle hooks or in components
Make sure you have set the url in your mqtt config in nuxt.config.ts. The URL is required.
- Verify your broker is running and accessible
- Make sure you're using a WebSocket URL (
ws://orwss://), not a plain MQTT URL (mqtt://) - Check the browser console for MQTT connection/error logs (the module logs
✅ MQTT connected,🔄 MQTT reconnecting, and❌ MQTT error)
- Make sure the topic string matches exactly (MQTT topics are case-sensitive)
- Verify your broker allows the subscription (check ACLs)
- Open the browser console to confirm the connection is established
mqtt: {
url: 'wss://broker.example.com:8084',
username: 'my_user',
password: 'my_password',
}