Framework Adapters
Nuxt
Nuxt 3 integration via @surfjs/web and Nitro server routes
Nuxt#
Nuxt 3 runs on Nitro, which uses Web Standard Request/Response — making it a natural fit for Surf. Use @surfjs/core in server routes and @surfjs/vue on the client.
pnpm add @surfjs/core @surfjs/vueServer Setup
Define Your Surf Instance
Create a shared Surf instance in a server utility file:
// server/utils/surf.tsimport { createSurf } from '@surfjs/core' export const surf = await createSurf({ name: 'My Nuxt App', commands: { search: { description: 'Search products', params: { query: { type: 'string', required: true }, limit: { type: 'number', default: 10 }, }, run: async ({ query, limit }) => { return db.products.search(query, { limit }) }, }, },})Nitro auto-imports from server/utils/, so surf is available in all server routes without explicit imports.
API Route Handler
Create a catch-all route that delegates to Surf's middleware:
// server/routes/surf/[...path].tsimport { surf } from '~/server/utils/surf' const handler = surf.middleware() export default defineEventHandler(async (event) => { const { req, res } = event.node return new Promise<void>((resolve) => { handler(req, res, () => { res.statusCode = 404 res.end(JSON.stringify({ error: 'Not Found' })) resolve() }) })})Discovery Endpoint
Surf agents discover your app via /.well-known/surf.json. Add a route that proxies to the Surf manifest:
// server/routes/.well-known/surf.json.tsimport { surf } from '~/server/utils/surf' const handler = surf.middleware() export default defineEventHandler(async (event) => { const { req, res } = event.node // Rewrite the URL so Surf's middleware recognizes this as a manifest request req.url = '/.well-known/surf.json' return new Promise<void>((resolve) => { handler(req, res, () => { res.statusCode = 404 res.end() resolve() }) })})Endpoints
With the routes above, your Nuxt app exposes:
| Method | Path | Description |
|--------|------|-------------|
| GET | /.well-known/surf.json | Manifest (discovery) |
| POST | /surf/execute | Command execution |
| POST | /surf/pipeline | Pipeline execution |
| POST | /surf/session/start | Start session |
| POST | /surf/session/end | End session |
Client-Side Integration
Use @surfjs/vue composables in your Nuxt pages and components:
SurfProvider Plugin
Create a Nuxt plugin to initialize the Surf runtime app-wide:
// plugins/surf.client.tsexport default defineNuxtPlugin(() => { // @surfjs/vue's SurfProvider handles initialization — // this plugin just ensures it's available as a client-only module.})Then wrap your app layout with SurfProvider:
<!-- layouts/default.vue --><template> <SurfProvider endpoint="https://myapp.com"> <slot /> </SurfProvider></template> <script setup lang="ts">import { SurfProvider } from '@surfjs/vue'</script>Using Commands in Pages
<!-- pages/index.vue --><script setup lang="ts">import { useSurf, useSurfCommands } from '@surfjs/vue' const { execute } = useSurf() // Register local commands for browser-based agentsuseSurfCommands({ 'theme.toggle': { mode: 'local', run: () => { document.documentElement.classList.toggle('dark') return { ok: true } }, },}) // Execute server commandsconst results = ref<unknown>(null) async function search(query: string) { results.value = await execute('search', { query })}</script>Real-Time State with Surf Live
For WebSocket-powered real-time state, add the url prop to SurfProvider:
<template> <SurfProvider endpoint="https://myapp.com" url="wss://myapp.com/surf/ws" > <slot /> </SurfProvider></template>Then subscribe to live state in any component:
<script setup lang="ts">import { useSurfState } from '@surfjs/vue' const metrics = useSurfState('metrics', { users: 0, events: 0 })</script> <template> <div>Online: {{ metrics.users }}</div></template>With Authentication
Pass an auth token through SurfProvider:
<template> <SurfProvider endpoint="https://myapp.com" :auth="userToken" > <slot /> </SurfProvider></template> <script setup lang="ts">import { SurfProvider } from '@surfjs/vue' const userToken = useCookie('auth-token')</script>Deployment Notes
| Feature | Vercel / Serverless | Node.js Server | Cloudflare Workers | |---------|--------------------|-----------------|--------------------| | Manifest + Discovery | ✅ | ✅ | ✅ | | Command execution | ✅ | ✅ | ✅ | | Pipelines + Sessions | ✅ | ✅ | ✅ | | SSE Streaming | ✅ | ✅ | ✅ | | WebSocket + Surf Live | ❌ | ✅ | ❌ |
⚠️ Surf Live requires a persistent server process. Serverless platforms do not support long-lived WebSocket connections. Deploy to a Node.js server (Railway, Fly.io, VPS) for real-time features.