This is a starter template for building a web application using Nuxt 4, Nuxt UI 4, Drizzle ORM, Resend and Better Auth. It provides a solid foundation for creating modern, scalable, and secure web applications.
- 🚀 Modern Tech Stack - Built with Nuxt 4, Vue 3, TypeScript
- 🔒 Secure Auth - Better Auth with OAuth2 social logins
- 💾 Enterprise Database - PostgreSQL with Drizzle ORM
- 📧 Email Integration - Built-in Resend support
- 📱 Responsive - Mobile-first design approach
- 🎯 Developer Experience - ESLint + TypeScript for better DX
### 1. Clone the repository
git clone https://github.com/zangetsu02/nuxt-ui-better-auth-template
cd nuxt-ui-better-auth-template
### 2. Install dependencies
pnpm i
### 3. Setup environment variables
cp .env.example .env
### 4. Setup database
docker compose up
### 5. Generate and apply database migrations
pnpm db:generate
pnpm db:migrate
### 6. Start the development server
pnpm devThe auth-schema file is located in drizzle/schema/auth-schema.ts. This file is generated by Better Auth and contains the necessary schema for authentication.
The command for generating the schema is:
npx @better-auth/cli@latest generate --config ./server/utils/auth.tsTo generate migrations, use the following command:
pnpm db:generateTo apply the migrations to your database, use:
pnpm db:migrateThe template includes a built-in pagination utility (server/utils/pagination.ts) for handling paginated API responses with Drizzle ORM.
- Type-safe pagination with TypeScript
- Standardized pagination metadata
- Easy integration with Drizzle queries
- Configurable page size with limits
// server/api/users.get.ts
import { db } from '~/server/database/db'
import { users } from '~/server/database/schema'
import {
withPagination,
queryWithCount,
createPaginatedResponse,
DEFAULT_PAGE,
DEFAULT_PAGE_SIZE,
MAX_PAGE_SIZE
} from '~/server/utils/pagination'
export default defineEventHandler(async (event) => {
// Get query parameters
const query = getQuery(event)
const page = Number(query.page) || DEFAULT_PAGE
const pageSize = Math.min(Number(query.pageSize) || DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE)
// Build your Drizzle query
let qb = db.select().from(users)
// Apply pagination
qb = withPagination(qb, page, pageSize)
// Execute query with count
const [data, total] = await queryWithCount(qb)
// Return paginated response
return createPaginatedResponse(data, page, pageSize, total)
}){
"data": [...],
"meta": {
"page": 1,
"pageSize": 20,
"total": 100,
"totalPages": 5,
"hasNextPage": true,
"hasPreviousPage": false
}
}If you find this project helpful, please consider:
- Giving it a star ⭐
This project is built upon these amazing open source projects:
- Nuxt - The Progressive Web Framework
- Nuxt UI - Fully styled and customizable components
- Resend - The email API for developers.
- Better Auth -The most comprehensive authentication framework for TypeScript
- Drizzle ORM - TypeScript ORM
- TailwindCSS - Utility-first CSS framework
- NuxSaas: For the inspiration
This project is licensed under the MIT License.