Project structure
See where pages, Convex functions, auth files, and settings live after the quick start.
After Protect data, the app has these files:
my-convex-app/
├── app/
│ ├── app.vue # header with sign-out, <NuxtPage />
│ └── pages/
│ ├── auth/
│ │ └── signin.vue # sign-in and sign-up form
│ └── index.vue # protected todo page
├── convex/
│ ├── _generated/ # generated by Convex; do not edit
│ ├── betterAuth/ # auth component; schema files are generated
│ ├── auth.config.ts # lets Convex accept session tokens
│ ├── auth.ts # createBetterConvexAuth
│ ├── convex.config.ts # registers the betterAuth component
│ ├── http.ts # /api/auth/* routes
│ ├── schema.ts # your tables
│ └── todos.ts # your queries and mutations
├── .env.example # committed; names only, secrets empty
├── .env.local # not committed; deployment, URLs, secrets
├── nuxt.config.ts
└── package.jsonKeep local settings in .env.local only. Convex commands read it. Run Nuxt with --dotenv .env.local so Nuxt reads the same file. Set production values in your hosting platform, not in a file.
Where code goes
app/: pages and components. They call the composables and show state. Hiding a button here does not protect data.convex/: functions that validate arguments, check the user, and read or write data. Put every permission check here.server/: Nuxt server routes. Add one only when you need a server-side secret, a webhook, or your own HTTP API. Pages do not need a server route to call Convex. See server routes.shared/: optional. Put validation schemas and types that bothapp/andconvex/use here.
Add Better Auth client plugins
The browser auth client works without extra setup. Some Better Auth plugins add client methods. To type and register them, create app/convex-auth.ts:
import { defineConvexAuthClient } from '@lupinum/better-convex-nuxt/better-auth/client'
export default defineConvexAuthClient({
plugins: [],
})The module looks for this file in the Nuxt srcDir, which is app/ in Nuxt 4. To use another path, set convex.auth.client in nuxt.config.ts. See Better Auth plugins.
Where tests go
- Convex tests for permission checks and data rules
- Nuxt tests for pages and route behavior
- Browser tests for the full sign-in flow
A browser test alone does not prove that Convex rejects other users. Test the permission check in Convex too.