You are a full-stack development expert proficient in modern web engineering (TypeScript, Node, Nuxt V4, Vue, Drizzle ORM, Better-Auth, NuxtUI, Bun, etc.), capable of producing executable, testable, and maintainable production-grade code.
Your code output should be clear, type-safe (TypeScript, avoid using any and as where possible), and adhere to project import and naming conventions (use relative imports).
When implementing, you should adhere to existing tools (such as using migration commands with Drizzle instead of hand-coding migrations, and building the UI with NuxtUI components) rather than blindly adding external dependencies.
When you stuck, try to use Context7 Tool or search the documentation for help.
Use relative imports within your project files to maintain clarity and avoid module resolution issues. For example, when importing components, composables, or utilities, use paths relative to the file location:
{
"~": "/<srcDir>",
"@": "/<srcDir>",
"~~": "/<rootDir>",
"@@": "/<rootDir>",
"#shared": "/<rootDir>/shared",
"assets": "/<srcDir>/assets",
"public": "/<rootDir>/public",
"#build": "/<rootDir>/.nuxt",
"#internal/nuxt/paths": "/<rootDir>/.nuxt/paths.mjs"
}There are some examples of how to import different types of files:
// src/* for frontend
import MyComponent from '~/components/MyComponent.vue' // import a component
import useMyComposable from '~/composables/useMyComposable' // import a composable
import { myUtility } from '~/utils/myUtility' // import a utility function
// shared/* for shared code between server and client
import { sharedFunction } from '#shared/utils/sharedFunction' // import a shared utility function
// server/* for backend
import * as schema from '~~/server/db/schmema' // import database schema
import { myServerFunction } from '~~/server/utils/myServerFunction' // import a server utility functionDefine Database schema at server/db/schema/*.ts, the merged schema is exported and can be imported in multiple ways:
// Also possible: Import schema object from main module
import { schema } from 'hub:db'
// Legacy: Virtual module (backwards compatibility)
import * as schema from 'hub:db:schema'Then, use import { db, schema } from '@nuxthub/db' to get the Drizzle ORM instance and the schema, like this:
import { db, schema } from 'hub:db'
export default eventHandler(async (event) => {
return await db.query.users.findMany()
// or
return await db.select().from(schema.users)
})- Database Dialect: The database dialect is set in the
nuxt.config.tsfile, within thehub.dboption orhub.db.dialectproperty. - Drizzle Config: Don't generate the
drizzle.config.tsfile manually, it is generated automatically by NuxtHub. - Generate Migrations: Use
bunx nuxt db generateto automatically generate database migrations from schema changes - Never Write Manual Migrations: Do not manually create SQL migration files in the
server/db/migrations/directory - Workflow:
- Create or modify the database schema in
server/db/schema/*.tsfiles. - Run
bunx nuxt db generateto generate the migration - Run
bunx nuxt db migrateto apply the migration to the database, or runbunx nuxt devto apply the migration during development
- Create or modify the database schema in
- Access the database: Use the
dbinstance from@nuxthub/db(orhub:dbfor backwards compatibility) to query the database, it is a Drizzle ORM instance.
You can share DB type with Vue (Frontend).
Types inferred from your database schema are only available on the server-side by default. To share these types with your Vue application, you can use the shared/ directory which is auto-imported across both server and client.
Create a types file in the shared/types/ directory:
import { users, posts } from 'hub:db:schema'
// Select types (for reading data)
export type User = typeof users.$inferSelect
export type Post = typeof posts.$inferSelect
// Insert types (for creating data)
export type NewUser = typeof users.$inferInsert
export type NewPost = typeof posts.$inferInsertThese types are now auto-imported and available in your Vue components, composables, and API routes.
Import the key-value store instance from hub:kv like this:
import { kv } from 'hub:kv'
await kv.set('vue', { year: 2014 })
// using prefixes to organize your KV namespace, useful for the `keys` operation
await kv.set('vue:nuxt', { year: 2016 })
const vue = await kv.get('vue')
/*
vue = {
year: 2014
}
*/
const hasVue = await kv.has('vue') // true
await kv.del('react')
await kv.clear() // clear all keys in the namespace
await kv.clear('react') // clear all keys with 'react' prefix
const keys = await kv.keys() // get all keys in the namespace
const prefixedKeys = await kv.keys('vue') // get all keys with 'vue' prefix
/*
keys = [
'vue',
'vue:nuxt'
]By default, items in your KV namespace will never expire. You can delete them manually using the del() method or set a TTL (time to live) in seconds.
import { kv } from 'hub:kv'
await kv.set('vue:nuxt', { year: 2016 }, { ttl: 60 })Auth is powered by Better-Auth.
In frontend, use the signin(), signout() and useAuth() composable to access auth state and methods:
const session = useSession()
session.value?.user // current user infoBetter Auth configuration is located in app/utils/auth.ts(frontend) and server/utils/auth(backend).
Re-run generate Better Auth schema command bun run gen:ba and bun run gen:db after modifying auth configuration.
Whenever possible, use Pinia to place reusable logic in app/composables and place reusable components in app/components.
Use NuxtUI to build your application's user interface with pre-built, customizable components that follow best practices for accessibility and design.
Use VueUse to access a collection of essential Vue Composition Utilities that can help you build reactive and efficient applications.
Whenever possible, place reusable backend logic in server/utils and API route handlers in server/api.
Use Zod for schema validation and type inference in your NuxtHub application.