- 🔐 Authentication with Lucia Auth
- 🗃️ Database ORM with Prisma
- 🐳 Docker setup for PostgreSQL and Dragonfly
- 🚀 Server Actions with Next Safe Action
- 📊 Schema validation with Zod
- 🛡️ Rate limiting
- 🎨 UI components with shadcn/ui
- 🔒 Protected and public pages/API routes
- 📋 Data table with server-side rendering
- 🔄 Cache invalidation
-
Clone the repository using degit:
npx degit dotyigit/boot-next my-next-app -
Install dependencies:
cd my-next-app npm install -
Set up environment variables:
- Copy
.env.exampleto.env - Update the variables in
.env
- Copy
-
Start the Docker containers:
docker compose up -dThis will start the PostgreSQL and Dragonfly (Redis replacement) containers.
-
Run database migrations:
npm run db:migrate -
Start the development server:
npm run dev
You can now access the application at http://localhost:3000.
- Pre-configured authentication system
- Login, register, and logout functionality
- Protected routes and API endpoints
To use authentication in your components:
- Import the
validateRequestfunction from@/lib/auth - Use it in server components or API routes to check authentication status
- Database schema defined in
prisma/schema.prisma - Models for User, Session, and Entry
To use Prisma in your application:
- Import the Prisma client from
@/lib/prisma - Use it to query the database in your server-side code
To update the database schema:
- Modify
prisma/schema.prisma - Run
npm run db:migrate
- PostgreSQL and Dragonfly (Redis replacement) containers
To start the containers:
docker compose up
unprotectedActionClientandprotectedActionClientfor handling server actions
To create a new server action:
- Create a new file (e.g.,
src/app/your-feature/actions.ts) - Import the appropriate action client
- Define your action using the client's schema and action methods
- Use the action in your components
Here is an example of a server action:
export const deleteEntry = protectedActionClient
.metadata({
actionName: "delete-entry",
})
.schema(deleteEntrySchema)
.action(async ({ parsedInput, ctx }) => {
const { id } = parsedInput;
const { user } = ctx;
// check if the entry belongs to the user
const entry = await prisma.entry.findUnique({
where: {
id,
userId: user.id,
},
});
if (!entry) {
return returnValidationErrors(deleteEntrySchema, {
_errors: ["Entry not found"],
});
}
await prisma.entry.delete({
where: {
id: entry.id,
},
});
revalidateTag("entries");
return {
status: "success",
message: "Entry deleted successfully",
};
});This starter kit uses Zod for schema validation, providing a type-safe and declarative way to validate data.
To use Zod in your components or actions:
- Define your schema using Zod's methods (e.g.,
z.object(),z.string(),z.number()). - Use the schema in your server actions or form validations.
- Handle any validation errors appropriately.
Here's an example of how to use Zod for form validation:
import { z } from "zod";
export const mySchema = z.object({
name: z.string(),
age: z.number(),
});
export type MySchemaValues = z.infer<typeof mySchema>;For more complex validations, you can use Zod's advanced features like .refine() for custom validations or .transform() for data transformation during validation.
To see how Zod is used in this starter kit, check the schema definitions in the following files:
src/app/(protected)/entries/schema.ts
- Automatic rate limiting for unprotected actions and API routes
To apply rate limiting to custom API routes:
- Import and use the
checkRateLimitfunction from@/lib/rate-limit
- Pre-configured UI components
To use a component:
- Import it from
@/components/ui - Use it in your TSX
- Layouts for handling authentication checks
To create a new protected page:
- Add it under the
src/app/(protected)directory
To create a public page:
- Add it directly under the
src/appdirectory
- Helper function for creating protected API routes
To create a protected API route:
- Create a new file in
src/app/api/your-route/route.ts - Use the
withAuthHandlerfunction from@/lib/api
- Reusable data table component with server-side data fetching
To use the data table:
- Define your columns
- Fetch data on the server
- Use the
DataTablecomponent in your page from@/components/ui/data-table
- Built-in cache invalidation using Next.js's
revalidateTagandrevalidatePath
To invalidate cache for a specific tag:
import { revalidateTag } from "next/cache";
revalidateTag("your-tag-name");Or, specific page:
import { revalidatePath } from "next/cache";
revalidatePath("/your-page");By following this manual, you can effectively use the features of this Next.js starter kit and develop new functionality as needed. Remember to adhere to best practices, maintain code quality, and keep your dependencies up to date.