Next.js 13+ introduces **Server Actions**, an innovative feature that simplifies server-side logic handling while keeping API calls efficient. When combined with **MySQL**, this enables developers to build powerful, server-driven applications with optimized database interactions. In this blog post, we'll walk through **integrating Next.js Server Actions with MySQL** to create a **CRUD (Create, Read, Update, Delete) application**. * * * ## **Why Use Server Actions in Next.js?** Traditionally, Next.js applications required API routes (`pages/api` or `app/api`) for server-side logic. With **Server Actions**, you can now handle form submissions and data mutations directly in the component without creating separate API endpoints. ### **Benefits of Server Actions** * **Simplified codebase**: No need for additional API routes. * **Improved performance**: Direct server-side execution reduces unnecessary client-server interactions. * **Built-in security**: Avoids exposing database credentials in the client. * * * ## **Step 1: Setting Up a Next.js Project** First, create a new Next.js project with TypeScript enabled: ```sh npx create-next-app@latest my-next-crud-app --typescript cd my-next-crud-app ``` * * * ## **Step 2: Install MySQL and Prisma ORM** To interact with MySQL, we’ll use **Prisma**, a powerful ORM for managing database queries in TypeScript. ### **Install Dependencies** ```sh npm install mysql2 @prisma/client npm install --save-dev prisma ``` ### **Initialize Prisma** Run the following command to generate a Prisma configuration: ```sh npx prisma init ``` This will create a `.env` file and a `prisma/schema.prisma` file. * * * ## **Step 3: Configure MySQL Connection** In your `.env` file, update the **DATABASE\_URL** with your MySQL credentials: ```env DATABASE_URL="mysql://user:password@localhost:3306/mydatabase" ``` Replace: * `user` with your MySQL username. * `password` with your MySQL password. * `mydatabase` with the database name. * * * ## **Step 4: Define a Prisma Model** Edit `prisma/schema.prisma` to define a **User** model: ```prisma generator client { provider = "prisma-client-js" } datasource db { provider = "mysql" url = env("DATABASE_URL") } model User { id Int @id @default(autoincrement()) name String email String @unique createdAt DateTime @default(now()) } ``` Now, apply the changes to your database: ```sh npx prisma migrate dev --name init ``` * * * ## **Step 5: Implement Server Actions for CRUD Operations** ### **1\. Create a User** In `app/actions.ts`, define a **server action** to insert a new user. ```typescript "use server"; import prisma from "@/lib/prisma"; export async function createUser(formData: FormData) { const name = formData.get("name") as string; const email = formData.get("email") as string; await prisma.user.create({ data: { name, email }, }); return { message: "User created successfully" }; } ``` ### **2\. Read Users** In `app/actions.ts`, define a function to fetch users. ```typescript export async function getUsers() { return await prisma.user.findMany(); } ``` ### **3\. Update a User** ```typescript export async function updateUser(id: number, name: string) { return await prisma.user.update({ where: { id }, data: { name }, }); } ``` ### **4\. Delete a User** ```typescript export async function deleteUser(id: number) { return await prisma.user.delete({ where: { id } }); } ``` * * * ## **Step 6: Build the Next.js UI with Server Actions** ### **User Form Component** In `app/page.tsx`, add a simple form to create users. ```tsx "use client"; import { useState } from "react"; import { createUser } from "./actions"; export default function Home() { const [message, setMessage] = useState(""); async function handleSubmit(event: React.FormEvent) { event.preventDefault(); const formData = new FormData(event.target as HTMLFormElement); const response = await createUser(formData); setMessage(response.message); } return (

Next.js MySQL CRUD

{message &&

{message}

}
); } ``` * * * ## **Step 7: Display Users in a List** Modify `app/page.tsx` to display users: ```tsx import { getUsers, deleteUser } from "./actions"; export default async function UserList() { const users = await getUsers(); async function handleDelete(id: number) { await deleteUser(id); } return (

Users List

    {users.map((user) => (
  • {user.name} ({user.email})
  • ))}
); } ``` * * * ## **Step 8: Testing and Running the App** To start your Next.js app, run: ```sh npm run dev ``` Visit `http://localhost:3000` to interact with the CRUD application. * * * ## **Conclusion** With **Next.js Server Actions and MySQL**, we built a simple CRUD application while keeping the backend logic minimal. Server Actions simplify API handling, reduce client-server interactions, and improve security by avoiding direct exposure of database logic. ## Follow me on: X: [@maxiujun](https://x.com/maxiujun) Threads.net [@xiujunma](https://www.threads.net/@xiujunma) BlueSky: [@maxiujun.bsky.social](https://bsky.app/profile/maxiujun.bsky.social)