Next.js Server Actions Integration with MySQL to Build a CRUD App
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:
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
npm install mysql2 @prisma/client
npm install --save-dev prisma
Initialize Prisma
Run the following command to generate a Prisma configuration:
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:
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:
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:
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.
"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.
export async function getUsers() {
return await prisma.user.findMany();
}
3. Update a User
export async function updateUser(id: number, name: string) {
return await prisma.user.update({
where: { id },
data: { name },
});
}
4. Delete a User
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.
"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 (
<div>
<h1>Next.js MySQL CRUD</h1>
<form onSubmit={handleSubmit}>
<input type="text" name="name" placeholder="Name" required />
<input type="email" name="email" placeholder="Email" required />
<button type="submit">Create User</button>
</form>
{message && <p>{message}</p>}
</div>
);
}
Step 7: Display Users in a List
Modify app/page.tsx
to display users:
import { getUsers, deleteUser } from "./actions";
export default async function UserList() {
const users = await getUsers();
async function handleDelete(id: number) {
await deleteUser(id);
}
return (
<div>
<h2>Users List</h2>
<ul>
{users.map((user) => (
<li key={user.id}>
{user.name} ({user.email})
<button onClick={() => handleDelete(user.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}
Step 8: Testing and Running the App
To start your Next.js app, run:
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.