nuxt-nats
GitHub提供 Nuxt 4/Nitro 项目中集成 NATS JetStream 的开发指南,涵盖配置、发布订阅、KV/对象存储及 AI Agent 集成的自动导入工具使用。
Trigger Scenarios
Install
npx skills add lithqube/nats-jetstream-claude-skills --skill nuxt-nats -g -y
SKILL.md
Frontmatter
{
"name": "nuxt-nats",
"description": "Use this skill whenever working in a Nuxt 4 \/ Nitro project that uses the nuxt-nats module to talk to NATS JetStream — configuring the module in nuxt.config (the `nats:` key), publishing events with jsPublish or corePublish, registering durable pull consumers with defineNatsConsumer, building a dead-letter consumer with defineDeadLetterConsumer, streaming to the browser with useEphemeralConsumer (SSE), using KV\/Object Store via useKV\/useObj, exposing or calling AI agents with defineNatsAgent\/useAgents, typing subjects via the NatsEvents interface, or the NUXT_NATS_WORKERS worker gate. Trigger on any of those symbols, on the env vars NUXT_NATS_SERVERS \/ NUXT_NATS_USER_JWT \/ NUXT_NATS_NKEY_SEED \/ NUXT_NATS_WORKERS, or when a Nuxt app needs server-side NATS messaging. Use this even if the user just says \"add NATS to my Nuxt app\". For raw @nats-io\/* client code outside Nuxt use jetstream-architecture; for server\/cluster deployment use jetstream-deployment; for the Synadia agent protocol details use nats-agent-fabric."
}
nuxt-nats
nuxt-nats is a Nuxt 4 / Nitro server-side module (config key nats) that owns the NATS JetStream connection lifecycle and gives you auto-imported server utilities for publishing, consuming, KV/Object Store, and the Synadia agent fabric. It wraps the modular @nats-io/* v3 client — you almost never call @nats-io/* directly in a nuxt-nats app.
It is server-only (Nitro): there are no browser composables (ADR-002). Publish and consume from server/ — plugins, API routes, and Nitro tasks.
What it gives you (auto-imported in server/)
| Utility | Purpose |
|---|---|
useNats() / useJetStream() / useJetStreamManager() |
raw connection / JS client / JSM, when you need to drop down |
useJetStreamIfAvailable() |
non-throwing useJetStream() — returns null before the connection is ready (see SSR lifecycle) |
jsPublish(subject, data, opts?) |
durable JetStream publish, typed via NatsEvents, with msgId dedup + client retry |
corePublish(subject, payload) |
fire-and-forget core NATS publish (no PubAck) |
defineNatsConsumer(opts) |
register a durable pull consumer (worker) |
defineDeadLetterConsumer(opts) |
build a DLQ by consuming max-deliver / terminated advisories from a stream |
useEphemeralConsumer(opts) |
request-scoped ordered ephemeral consumer (SSE) |
useKV(bucket, opts?) / useObj(bucket, opts?) |
KV bucket / Object Store, cached per process |
defineNatsAgent(opts) / useAgents() |
host or call AI agents on the Synadia Agent Protocol |
Reference files
Read the one you need — don't load them all:
references/configuration.md— the fullnats:module option reference, env-var overrides, the auth priority chain, TLS, JetStream domain/prefix, and the provisioning stance (provision). Read when setting up or debugging module config.references/publishing.md—jsPublishvscorePublish, theNatsEventstyped-subject augmentation,msgIddedup, and publish retry. Read when producing events.references/consumers.md—defineNatsConsumer, theNUXT_NATS_WORKERSgate, ack/nak/term handling,defineDeadLetterConsumer, anduseEphemeralConsumerfor SSE. Read when consuming.references/kv-object.md—useKV/useObj, and their real gotchas (Object Store wants aReadableStream, KV TTL units). Read for state/blob storage.references/agents.md—defineNatsAgent/useAgentson the Synadia Agent Protocol. Read when building an agent; defer to thenats-agent-fabricskill for the wire protocol itself.references/gotchas.md— the SSR/Nitro lifecycle race, reconnect-storm status semantics, Nitro externals, provisioning races, and testing with Testcontainers. Read this before shipping to production; it's where the non-obvious failures live.
Minimal setup
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['nuxt-nats'],
nats: {
servers: ['nats://localhost:4222'], // override in prod via NUXT_NATS_SERVERS (all cluster nodes)
// auth is normally injected via env: NUXT_NATS_USER_JWT + NUXT_NATS_NKEY_SEED
streams: [ // DESCRIBE streams; do not let the app own them in prod
{ name: 'ORDERS', subjects: ['orders.>'], provision: 'never' },
],
},
})
// server/api/orders.post.ts — publish
export default defineEventHandler(async (event) => {
const body = await readBody(event)
await jsPublish('orders.created', body, { msgId: body.id }) // msgId => Nats-Msg-Id dedup
return { ok: true }
})
// server/plugins/order-worker.ts — consume (runs only when NUXT_NATS_WORKERS=true)
export default defineNitroPlugin(() => {
defineNatsConsumer({
stream: 'ORDERS',
durable: 'order-processor', // binds an EXISTING durable by default (IaC owns its config)
async handler(data, msg) {
await process(data)
// handler return = ack; throw = nak with backoff; see references/consumers.md
},
})
})
Core principles
- Server-side only. Publish/consume from
server/. There are no client composables; don't try touseNats()in a Vue component. - The worker gate is deliberate. Consumers and agents run only when
NUXT_NATS_WORKERS=true. Serverless/edge deployments publish fine but must not run long-lived pull loops. The recommended topology is a serverless publisher + a separate persistent worker process. If your consumer "never fires", check this first. provision: 'never'in production. A stream/consumer config is server-side state that belongs in IaC (an idempotentstreams.shor Helm), not in N racing app replicas.provision: 'startup'is for dev;'update'races on rolling deploys. Thestreams:block in config is best read as documentation of a stream some other process owns.defineNatsConsumerbinds; it does not enforce. By default it binds an existing durable —filterSubjects/ackPolicyyou pass are not sent to the broker unless the durable is being created (provision: 'startup'). The live durable's config wins; a drift test against a real broker is the only thing that catches a mismatch.- NATS has no dead-letter queue.
maxDeliver= retry then stop, not "route to a DLQ". UsedefineDeadLetterConsumer()(advisory capture) if you need one — seereferences/consumers.md. Never write a comment claiming redelivery auto-routes todlq.*; it doesn't. - Type your subjects. Augment
NatsEventsin aserver/**/*.d.tsso everyjsPublishis checked. Seereferences/publishing.md. - Respect the SSR lifecycle race. Nitro doesn't await async server plugins in order, so the connection may not be ready when a later plugin runs. Use
useJetStreamIfAvailable()/ the module's readiness wait, never a bareuseJetStream()at plugin top level. Seereferences/gotchas.md.
Version History
- 5001f06 Current 2026-09-22 13:05


