This guide walks through configuring a Nuxt 3/4 application for static Single Page Application (SPA) generation, setting up local development proxying with Nitro, integrating the TypeScript SDK (@kodall/kodall-client), and deploying the build to a Kodall instance using @kodall/kodall-deploy.
Deployed on Kodall instance at /nuxt
Currently running in shared demo mode with the public API key. Create a private 24-hour sandbox with 1-click to test creating, editing, and deleting records without interference.
Install @kodall/kodall-client and @kodall/kodall-deploy in your Nuxt project:
pnpm add @kodall/kodall-client
pnpm add -D @kodall/kodall-deploy
npm install @kodall/kodall-client
npm install -D @kodall/kodall-deploy
yarn add @kodall/kodall-client
yarn add -D @kodall/kodall-deploy
bun add @kodall/kodall-client
bun add -d @kodall/kodall-deploy
Set ssr: false to enable static Single Page Application (SPA) generation. Configure nitro.devProxy using @kodall/kodall-deploy's built-in getNitroProxy() helper to automatically resolve your instance URL from kodall-webapp.config.json:
import { kodallProxyNuxt, getNitroProxy } from '@kodall/kodall-deploy'
export default defineNuxtConfig({
// Disable server-side rendering for static SPA output
ssr: false,
// Option A: 1-Line Nuxt Module (Recommended)
modules: [
kodallProxyNuxt() // Automatically resolves instance from default_env
]
// Option B: Nitro devProxy Helper
// nitro: {
// devProxy: getNitroProxy()
// }
// Option C: Manual Nitro Proxy (Without Helper Package)
// nitro: {
// devProxy: {
// '/auth': { target: 'https://dev.kodall.yourcompany.com/auth', changeOrigin: true, secure: true },
// '/rest': { target: 'https://dev.kodall.yourcompany.com/rest', changeOrigin: true, secure: true },
// '/storage': { target: 'https://dev.kodall.yourcompany.com/storage', changeOrigin: true, secure: true }
// }
// }
})
kodallProxyNuxt() automatically reads the target instance URL and custom proxy_paths from default_env in kodall-webapp.config.json. To target a specific environment, pass { env: 'staging' } or explore the Local Dev Proxy Suite.Create a Nuxt composable to provide a shared, reactive instance of KodallClient:
import { KodallClient } from '@kodall/kodall-client'
export const useKodall = () => {
return useState<KodallClient>('kodall-client', () => new KodallClient())
}
new KodallClient() requires no hardcoded baseUrl or credentials.Create kodall-webapp.config.json in the root of your project. Nuxt's nuxt generate emits static files into ./.output/public:
{
"web_app_name": "Nuxt Portal",
"web_app_path": "/",
"dist_path": "./.output/public",
"default_env": "dev",
"environments": {
"dev": {
"type": "dev",
"instance": "https://dev.kodall.yourcompany.com",
"api_key": "dev-api-key-here"
},
"prod": {
"type": "prod",
"instance": "https://kodall.yourcompany.com",
"api_key": "prod-api-key-here"
}
}
}
https://docs-demo.kodall.io. Enter the base URL of your own Kodall instance deployed from the Kodall Cloud Console.Support both API Key (stateless bearer token) and Username/Password (cookie session), restoring the session on page refresh without UI flicker:
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { KodallClient, isProblem } from '@kodall/kodall-client'
const isInitializing = ref(true)
const isAuthenticated = ref(false)
const credentials = reactive({ apiKey: '', username: '', password: '' })
function getClient(customKey?: string): KodallClient {
return new KodallClient({ apiKey: customKey || credentials.apiKey || undefined })
}
// Connect with API Key
async function handleConnectApiKey(keyInput?: string) {
const key = keyInput || credentials.apiKey
if (!key.trim()) return
const client = getClient(key)
const result = await client.fetch('FETCH todo (key) LIMIT 1')
if (!isProblem(result)) {
isAuthenticated.value = true
localStorage.setItem('kodall_is_logged_in', 'true')
localStorage.setItem('kodall_auth_mode', 'apikey')
localStorage.setItem('kodall_api_key', key)
}
}
// Login with Username & Password
async function handleLoginBasic(uInput?: string, pInput?: string) {
const u = uInput || credentials.username
const p = pInput || credentials.password
if (!u || !p) return
const client = getClient('')
const result = await client.auth({ user: u, password: p }, { roles: true })
if (!isProblem(result)) {
isAuthenticated.value = true
localStorage.setItem('kodall_is_logged_in', 'true')
localStorage.setItem('kodall_auth_mode', 'basic')
}
}
// Restore session on mount (anti-flicker loading splash)
onMounted(async () => {
try {
const params = new URLSearchParams(window.location.search)
const urlApiKey = params.get('apiKey')
if (urlApiKey) credentials.apiKey = urlApiKey
if (localStorage.getItem('kodall_is_logged_in') === 'true') {
const mode = localStorage.getItem('kodall_auth_mode')
if (mode === 'basic') await handleLoginBasic()
else await handleConnectApiKey()
}
} finally {
isInitializing.value = false
}
})
</script>
Fetch hierarchical parent-child relationships in a single FETCH query (e.g. Master todo with joined todo_item child subtasks) and create master-detail graphs:
// 1. Fetch joined parent-child rows
const result = await client.fetch<any>(`
FETCH todo (key, title, is_completed) {
todo_item TO id_todo (key AS item_key, description, is_completed AS item_completed)
}
ORDER BY key DESC
LIMIT 100
`)
// 2. Group flat rows into structured tree objects
function groupJoinedTodos(rows: any[]) {
const map = new Map<number, any>()
for (const row of rows) {
if (!map.has(row.key)) {
map.set(row.key, {
key: row.key,
title: row.title,
is_completed: row.is_completed,
children: { todo_todo_item: [] }
})
}
if (row.item_key != null) {
map.get(row.key).children.todo_todo_item.push({
key: row.item_key,
description: row.description,
is_completed: row.item_completed
})
}
}
return Array.from(map.values())
}
// 3. Create parent entity and child items atomically
await client.create({
entity_name: 'todo',
properties: {
title: 'Launch Web Application',
is_completed: 0
},
children: {
todo_todo_item: [
{ entity_name: 'todo_item', properties: { description: 'Configure proxy', is_completed: 1 } },
{ entity_name: 'todo_item', properties: { description: 'Deploy application', is_completed: 0 } }
]
}
})
Upload and download files directly using Kodall's storage endpoints:
// Upload a file (Blob or File instance from <input type="file">)
const response = await fetch('/storage', {
method: 'POST',
headers: {
'Content-Type': selectedFile.type || 'application/octet-stream',
'X-File-Name': encodeURIComponent(selectedFile.name)
},
body: selectedFile
})
const storageRecord = await response.json()
console.log('Stored File ID:', storageRecord.id)
Add static generation and deployment scripts to package.json:
{
"scripts": {
"dev": "nuxt dev",
"build": "nuxt build",
"generate": "nuxt generate",
"deploy": "nuxt generate && kodall-deploy -e dev",
"deploy:prod": "nuxt generate && kodall-deploy -e prod"
}
}
Execute the deployment command for your target environment:
# Deploy to development environment
pnpm deploy
# Or deploy to production
pnpm run deploy:prod
# Or run interactively
npx kodall-deploy
kodall-deploy will validate ./.output/public, package the static assets, upload the archive to Kodall storage, update the web_app entity, and run a live HTTP health check ping.
If your app is deployed to a subpath (e.g. "web_app_path": "/portal"), configure Nuxt's app.baseURL:
export default defineNuxtConfig({
ssr: false,
app: {
baseURL: '/portal/'
}
})
Every deployment is tracked in Kodall storage. You can inspect previous versions and instantly roll back to any prior build without rebuilding:
# Inspect live status across instances
npx kodall-deploy --status
# View deployment history
npx kodall-deploy --history -e prod
# Roll back to the previous deployment
npx kodall-deploy --rollback -e prod
Missing index.html in .output/publicnuxt generate was not run before deployment.nuxt generate (or run npx nuxi generate) before kodall-deploy.CORS Errors During Local Development/auth, /rest, /storage) and verify nitro.devProxy in nuxt.config.ts.CI/CD & Automation
Automate frontend deployments to Kodall with ready-to-run CI/CD pipelines, live health checks, instant rollbacks, and the Programmatic TypeScript API.
Vue 3 (Vite)
Step-by-step guide to building, proxying, and deploying standalone Vue 3 Vite applications to a Kodall instance with @kodall/kodall-deploy.