better-convex-nuxt
v0.3.4
Published
Full-featured Convex integration for Nuxt with SSR, real-time subscriptions, authentication, and permissions
Downloads
524
Maintainers
Readme
Better Convex Nuxt
Full-featured Convex integration for Nuxt with SSR, real-time subscriptions, authentication, and permissions.
[!NOTE] Work In Progress This module is rapidly evolving. While we are using it in our own apps, features and APIs are subject to change as we refine the best patterns for Nuxt + Convex.
Contributions and PRs to help improve the library, playground or docs are highly appreciated! 🙏
Features
- Real-time Queries - Fetch data with SSR, then upgrade to WebSocket subscriptions
- Optimistic Updates - Instant UI feedback with automatic rollback on failure
- Authentication - Better Auth integration with email/password, OAuth, and magic links
- Permissions - Role-based access control with ownership rules
- SSR Support - Server-side rendering with hydration
- Type Safety - Full TypeScript inference from your Convex schema
Quick Setup
Install the module:
pnpm add better-convex-nuxtUsage
Queries
<script setup lang="ts">
import { api } from '~/convex/_generated/api'
// Real-time subscription with SSR support
const { data: tasks, status } = await useConvexQuery(api.tasks.list, { status: 'active' })
</script>
<template>
<ul v-if="status === 'success'">
<li v-for="task in tasks" :key="task._id">
{{ task.text }}
</li>
</ul>
</template>Mutations
<script setup lang="ts">
import { api } from '~/convex/_generated/api'
const { execute, pending } = useConvexMutation(api.tasks.create, {
optimisticUpdate: (localStore, args) => {
updateQuery({
query: api.tasks.list,
args: {},
localQueryStore: localStore,
updater: (current) =>
current ? [{ _id: 'temp', text: args.text, completed: false }, ...current] : [],
})
},
})
await execute({ text: 'Ship my app' })
</script>Authentication
<script setup lang="ts">
const { isAuthenticated, user } = useConvexAuth()
const authClient = useAuthClient()
async function handleLogin() {
await authClient.signIn.social({ provider: 'github' })
}
</script>
<template>
<div v-if="isAuthenticated">Welcome, {{ user?.name }}!</div>
<button v-else @click="handleLogin">Sign in with GitHub</button>
</template>Composables
| Composable | Description |
| -------------------------- | ---------------------------------------------------- |
| useConvexQuery | Execute queries with SSR and real-time subscriptions |
| useConvexMutation | Execute mutations with optimistic updates |
| useConvexAction | Execute Convex actions |
| useConvexPaginatedQuery | Paginated queries with loadMore() |
| useConvexFileUpload | Upload files to Convex storage with progress |
| useConvexUploadQueue | Queue uploads with controlled concurrency |
| useConvexStorageUrl | Get reactive URLs for stored files |
| useConvexAuth | Authentication state (user, token, isAuthenticated) |
| useConvexConnectionState | WebSocket connection status |
| createPermissions | Build app-specific permission composables |
| useConvex | Access raw ConvexClient instance |
Components
| Component | Description |
| ------------------------- | ------------------------------------------- |
| <ConvexAuthenticated> | Renders content only when authenticated |
| <ConvexUnauthenticated> | Renders content only when not authenticated |
| <ConvexAuthLoading> | Renders content during auth state loading |
| <ConvexAuthError> | Renders content when auth resolution fails |
Documentation
Visit better-convex-nuxt.vercel.app for full documentation including:
Contributing
# Install dependencies
pnpm install
# Generate type stubs
pnpm dev:prepare
# Develop with the playground
pnpm dev
# Run tests
pnpm test
# Lint
pnpm lintAcknowledgements
- File upload composables inspired by nuxt-convex by @onmax
