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:
userwith your MySQL username.passwordwith your MySQL password.mydatabasewith 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.
Follow me on:
X: @maxiujun
Threads.net @xiujunma
BlueSky: @maxiujun.bsky.social
Read Next
How to Configure SSH on FreeBSD for Maximum Security
Secure Shell (SSH) is an essential tool for managing servers remotely, but an improperly configured SSH server can expose your system to serious risks. In this post, we’ll walk
How to Deploy a Next.js Application with Nginx on FreeBSD
How to Deploy a Next.js Application with Nginx on FreeBSD Next.js, a popular React framework for building server-rendered applications, offers robust features like static generation, server-side rendering, and