Nuxt
Nuxt Use @enfyra/sdk-nuxt for a third-party Nuxt 3 or Nuxt 4 application. It configures the same-origin Enfyra bridge, creates one SDK client per SSR request, forwards auth cookies safely, and auto-imports SDK composables. This package is for your own Nuxt application. It is not
Nuxt
Use @enfyra/sdk-nuxt for a third-party Nuxt 3 or Nuxt 4 application. It configures the same-origin Enfyra bridge, creates one SDK client per SSR request, forwards auth cookies safely, and auto-imports SDK composables.
This package is for your own Nuxt application. It is not the API used by Vue extensions running inside Enfyra Admin.
Install
yarn add @enfyra/sdk-nuxt @enfyra/sdk-core
Set the private Enfyra App origin:
ENFYRA_APP_URL=https://admin.example.com
Enable the module:
export default defineNuxtConfig({
modules: ['@enfyra/sdk-nuxt'],
})
That is the complete default setup. Do not repeat the same URL in nuxt.config.ts.
If you deliberately prefer configuration over an environment variable, set enfyra.appUrl instead:
export default defineNuxtConfig({
modules: ['@enfyra/sdk-nuxt'],
enfyra: {
appUrl: 'https://admin.example.com',
},
})
The option overrides ENFYRA_APP_URL when both exist. Normally, choose one source.
Optional Proxy Prefix
The browser prefix defaults to /enfyra. Change it only when that path conflicts with your app:
export default defineNuxtConfig({
modules: ['@enfyra/sdk-nuxt'],
enfyra: {
routePrefix: '/backend',
},
})
The module keeps the private App origin server-only and exposes only the local prefix to the browser.
Call Enfyra Directly
All SDK composables are auto-imported:
<script setup lang="ts">
interface Article {
id: number
title: string
status: string
}
const client = useEnfyra()
const { data: articles, error, refresh } = await useAsyncData(
'published-articles',
async () => {
const result = await client
.from<Article>('articles')
.select(['id', 'title', 'status'])
.filter({ status: { _eq: 'published' } })
.sort('-createdAt')
.limit(20)
.execute()
return result.data
},
)
</script>
useEnfyra() returns the original EnfyraClient. Use it directly for custom routes, query transforms, storage, or any core capability.
Authentication
<script setup lang="ts">
const {
user,
isAuthenticated,
pending,
error,
login,
logout,
refresh,
oauthLogin,
} = useAuth()
await refresh()
async function signIn(email: string, password: string) {
const result = await login({ email, password, remember: true })
if (result) await navigateTo('/dashboard')
}
</script>
Only a 401 clears the current user. A network or server failure remains available through error.
Start OAuth from a browser action:
oauthLogin('google')
The helper uses the current browser URL as the post-login redirect.
Client-Reactive Queries
Use useQuery() for a query that should execute after the component mounts in the browser:
const {
data,
error,
pending,
status,
meta,
refresh,
} = useQuery<Article[]>('articles', {
select: ['id', 'title', 'status'],
filter: { status: { _eq: 'published' } },
sort: '-createdAt',
limit: 20,
meta: ['totalCount'],
})
useQuery() runs from onMounted; it is not an SSR data-fetching replacement. For server-rendered page data, use useEnfyra() inside Nuxt useAsyncData() as shown above.
Set immediate: false when the user must choose filters first:
const query = useQuery<Article[]>('articles', {
immediate: false,
limit: 20,
})
await query.refresh()
Mutations
const createArticle = useMutation<Article>('articles', {
operation: 'insert',
onSuccess: () => refreshNuxtData('published-articles'),
})
await createArticle.execute({
data: { title: 'New article', status: 'draft' },
})
Update and delete:
const updateArticle = useMutation<Article>('articles', {
operation: 'update',
})
await updateArticle.execute({ id: articleId, data: { status: 'published' } })
const deleteArticle = useMutation('articles', {
operation: 'delete',
})
await deleteArticle.execute({ id: articleId })
For custom actions, use the original client:
const client = useEnfyra()
await client.post('/articles/archive', { articleId })
Response Transformation
const client = useEnfyra()
const { data } = await client
.from<Article>('articles')
.transform((value) => {
const rows = Array.isArray(value) ? value : [value]
return rows.map((row) => ({ ...row, title: row.title.trim() }))
})
.execute()
Global transformers can be registered once in a Nuxt plugin using the injected client:
export default defineNuxtPlugin(() => {
const client = useEnfyra()
client.onError((error) => {
reportError(error)
return error
})
})
Storage
const { upload, uploading, download, getDownloadUrl, getFolderTree } = useStorage()
const record = await upload(file, {
folder: folderId,
title: file.name,
})
Use useEnfyra().storage.getStorageConfigs() when the user is allowed to select a storage backend.
Realtime
const realtime = useWebSocket('notifications', { immediate: true })
watch(realtime.connected, (connected) => {
if (!connected) return
realtime.on('notification:created', (payload) => {
console.log(payload)
})
})
Your deployment still needs the Socket.IO transport proxy when realtime is used. The REST module route rule does not replace the WebSocket transport path.
Deployment Checklist
- Set
ENFYRA_APP_URLin the server runtime environment. - Do not expose the private App origin as a public runtime variable.
- Keep the chosen route prefix stable because OAuth cookies depend on it.
- Do not add a second route rule or cookie handler for the same SDK prefix.
- Verify login,
/me, logout, OAuth callback, SSR refresh, and one protected data request after deployment.