Using Nuxt with Agentuity

Add Agentuity service clients, local development, and deployment metadata to a Nuxt app

Start with a normal Nuxt app. Agentuity adds service clients, local development support, and deploy validation around Nitro server routes and build output.

Create a Starter

npm create agentuity -- --name my-nuxt-app --framework nuxt
cd my-nuxt-app

The starter runs nuxi init, adds @agentuity/cli, a deploy script, and an optional AI example. It uses Nuxt's server/api/ convention for server routes, the same shape documented by Nuxt's own server directory guide.

If you choose the AI example, the key files are:

FilePurpose
server/api/translate.post.tsNitro route that handles POST /api/translate
app/app.vueUI that calls the API route with $fetch
nuxt.config.tsNuxt configuration in the normal Nuxt shape

Import an Existing App

For an existing Nuxt app, add the CLI and import the project:

npm install -D @agentuity/cli
npx agentuity project import --validate-only
npx agentuity project import

npm install -D installs the CLI as a project-local dev dependency, not a global install. Use npx to run that local CLI. For Bun, pnpm, and Yarn equivalents, see Local versus global CLI.

agentuity project import registers the app and writes the local project metadata that agentuity deploy expects. Run it once before the first deploy for existing apps.

What Agentuity adds

AreaNuxt keepsAgentuity adds
routingNitro handlers in server/api/service clients imported in server-only files
local devnuxt devagentuity dev supplies service credentials
buildNitro output under .output/agentuity build runs the build and packages launch metadata
deploythe Nitro server entryagentuity deploy ships the packaged app

Add a Service Client and AI Gateway Call

Use standalone service clients directly from Nitro routes. Files under server/api/ are automatically prefixed with /api, and the .post.ts suffix limits this example to POST requests.

The route below uses AIGatewayClient for the model call. The project SDK key authenticates the request, and the model ID is app configuration or request input.

npm install @agentuity/aigateway @agentuity/keyvalue arktype
typescriptserver/api/translate.post.ts
import { AIGatewayClient } from '@agentuity/aigateway';
import { KeyValueClient } from '@agentuity/keyvalue';
import { type } from 'arktype';
import { defineEventHandler, getCookie, readBody, setCookie, setResponseStatus } from 'h3';
 
const DEFAULT_MODEL = 'openai/gpt-5.4-mini';
const HISTORY_NAMESPACE = 'translation-history';
const SESSION_COOKIE = 'agentuity_session';
const SESSION_TTL_SECONDS = 60 * 60 * 24 * 30;
 
interface HistoryEntry {
  readonly model: string;
  readonly sessionId: string;
  readonly text: string;
  readonly timestamp: string;
  readonly toLanguage: string;
  readonly translation: string;
}
 
interface HistoryState {
  readonly history: readonly HistoryEntry[];
  readonly translationCount: number;
}
 
// Validate the request body at the boundary before using any values
const requestSchema = type({
  text: 'string',
  toLanguage: 'string',
  'model?': 'string',
});
 
const kv = new KeyValueClient(); 
const gateway = new AIGatewayClient(); 
 
export default defineEventHandler(async (event) => {
  const rawBody: unknown = await readBody(event);
  const parsed = requestSchema(rawBody);
 
  if (parsed instanceof type.errors) {
    setResponseStatus(event, 400);
    return { error: 'text and toLanguage are required' };
  }
 
  const input = parsed;
  const model = input.model ?? DEFAULT_MODEL;
 
  // Read or create a session cookie so history is scoped per browser session
  const sessionId = getCookie(event, SESSION_COOKIE) ?? crypto.randomUUID();
  setCookie(event, SESSION_COOKIE, sessionId, {
    httpOnly: true,
    maxAge: SESSION_TTL_SECONDS,
    path: '/',
    sameSite: 'lax',
    // set secure when running in production
    secure: process.env.NODE_ENV === 'production',
  });
 
  const result = await gateway.completeText({ 
    model,
    messages: [
      {
        role: 'user',
        content: `Translate to ${input.toLanguage}:\n\n${input.text}`,
      },
    ],
  });
 
  if (!result.hasText) {
    setResponseStatus(event, 502);
    return { error: 'model returned no text' };
  }
 
  const translation = result.text;
 
  // Append to the per-session history stored in KV, keeping the last 5 entries
  const previous = await kv.get<HistoryState>(HISTORY_NAMESPACE, sessionId);
  const history = [
    ...(previous.exists ? previous.data.history : []),
    {
      model,
      sessionId,
      text: input.text,
      timestamp: new Date().toISOString(),
      toLanguage: input.toLanguage,
      translation,
    },
  ].slice(-5);
  const translationCount = (previous.exists ? previous.data.translationCount : 0) + 1;
 
  await kv.set(HISTORY_NAMESPACE, sessionId, { history, translationCount }, { ttl: SESSION_TTL_SECONDS }); 
 
  return {
    translation,
    history,
    model,
    translationCount,
  };
});

KeyValueClient reads AGENTUITY_SDK_KEY from the environment. Run with agentuity dev for local development so the linked project key is available to Nitro routes.

Use the model id exactly as it appears in the AI Gateway model catalog. Use a provider SDK directly only when the endpoint depends on provider-specific APIs.

Call from the Frontend

Call the Nitro route from app/app.vue using Nuxt's built-in $fetch:

vueapp/app.vue
<script setup lang="ts">
const text = ref('Welcome to Agentuity');
const toLanguage = ref('Spanish');
const translation = ref('');
const history = ref<Array<{ text: string; translation: string; toLanguage: string }>>([]);
 
async function translate(): Promise<void> {
  const result = await $fetch<{
    translation: string;
    history: typeof history.value;
  }>('/api/translate', {
    method: 'POST',
    body: { text: text.value, toLanguage: toLanguage.value },
  });
 
  translation.value = result.translation;
  history.value = result.history;
}
</script>
 
<template>
  <div>
    <textarea v-model="text" />
    <select v-model="toLanguage">
      <option>Spanish</option>
      <option>French</option>
      <option>German</option>
    </select>
    <button @click="translate()">Translate</button>
    <p v-if="translation">{{ translation }}</p>
  </div>
</template>

Run Locally

Run through Agentuity. When the linked project key is available, the CLI supplies AGENTUITY_SDK_KEY to the Nuxt process:

agentuity dev

Smoke-test the Nitro route directly:

curl http://localhost:3000/api/translate \
  -H "content-type: application/json" \
  -d '{"text":"Hello","toLanguage":"Spanish"}'

Deployed Environment Variables

Configure the variables your deployed app needs. Direct AIGatewayClient calls use AGENTUITY_SDK_KEY; the model ID in this example is normal app configuration or request input.

VariableUsed by
AGENTUITY_SDK_KEYAgentuity service clients and @agentuity/aigateway
DATABASE_URLdatabase Nitro routes
AWS_*object storage Nitro routes; see Object Storage for exact variables

Validate Before Deploy

Run the framework build when you want Nuxt-only feedback, then run the Agentuity build. agentuity build runs the framework build during packaging and writes .agentuity/launch.json.

npm run build
npx agentuity build

Nuxt is detected as its own framework (nuxt, nuxt3, nuxt-edge, or nuxt-nightly in dependencies). The build adapter packages the Nitro output. Verify the metadata points at the right paths:

cat .agentuity/launch.json

The Nitro build produces two output directories:

PathContents
.output/serverNitro server bundle, entry is server/index.mjs
.output/publicStatic assets for CDN or edge delivery

launch.json must reference the server/index.mjs entry inside .output/server. If it points at a static _serve.js helper, the packaged output is not serving Nitro routes.

Deploy only after the framework build, Agentuity build, and a local packaged validation of / and one Nitro route pass:

agentuity deploy --confirm

Common Gotchas

SymptomCheck
Route exists locally but returns 404 after deployConfirm the file is under server/api/, not server/routes/; only server/api/ gets the /api prefix
$fetch('/api/...') works locally but 404s after deployInspect .agentuity/launch.json: processes[0].command must run .output/server/index.mjs
Service client returns auth errorsRun with agentuity dev or set AGENTUITY_SDK_KEY in the environment
Model call returns an auth errorVerify AGENTUITY_SDK_KEY is available to the Nitro process. See AI Gateway
Server credentials leak to the browserKeep KeyValueClient and AIGatewayClient instantiation in server/api/ or other server-only files; Nitro does not bundle server files into the client
Cookie flags rejected by browsersecure: true requires HTTPS; for local testing use secure: process.env.NODE_ENV !== 'development'

Framework Docs

Next Steps