Next JS Server Actions Integration with MySQL to Build CURD App

Dr. Vipin Kumar
5 min readNov 22, 2023

Next.js is a Full Stack based robust framework built on React JS that simplifies and significantly improves the building of modern front-end and back-end web applications. It combines the best features of Dynamic Rendering/Server-Side-Rendering (SSR) and Static Rendering/Client-Side-Rendering (CSR), and also offering solid flexibility and performance optimization.

SERVER ACTIONS

Server Actions are new feature introduced in Next.js 14.0 or above, built on React Actions. They enable server-side data mutations like PHP, JSP and ASP.NET, reduced client-side JavaScript, and progressively enhanced forms. They can be easily defined inside Server Components and called from Client Components.

Benefits of SERVER ACTIONS

1. Allow Server Side mutations without unnecessary API endpoints.

2. Reduce Client-Side JavaScript.

3. Support Progressively Enhanced Forms.

How SERVER ACTIONS Works

With Server Actions, you don’t need to manually create API endpoints. Instead, you define asynchronous server functions that can be called directly from your components. Server Actions can be defined in Server Components or called from Client Components. Defining the action in a Server Component allows the form to function without JavaScript, providing progressive enhancement.

Let’s make a web application to understand SERVER ACTIONS in Next JS 14.0 or Above

For designing web form to take input or performing CURD operation, like Create, Update, and Delete, or Reading information from MySQL as shown in image given below, we need to write code in Next JS, for creating such kind of screen in Next JS, firstly you need to create a route and write code in page.js, for that I created this route “http://localhost:3000/CURDMySQL” and code of page.js is as given below:

//page.js code

import React from “react”;

import DisplayStudentInfo from “./DisplayStudentInfo”;

import ModifyStudent from “./ModifyStudent”;

const page = () => {

return (

<div>

<h2 className=”text-center”>MySQL with Server Action in Next JS</h2>

<ModifyStudent />

<DisplayStudentInfo />

</div>

);

};

export default page;

In this page.js, I used two component ModifyStudent and DisplayStudentInfo, code for ModifyStudent component is given as below:

//ModifyStudent Component Code

“use client”;

import React from “react”;

import { useFormStatus, useFormState } from “react-dom”;

import Mysqlserveraction from “./mysqlserveraction”;

const initialState = {

message: null,

};

const ModifyStudent = () => {

const [state, formAction] = useFormState(Mysqlserveraction, initialState);

const { pending } = useFormStatus();

return (

<div className=”container “>

<form

name=”studentf”

method=”post”

action={formAction}

className=”badge bg-warning d-flex flex-column d-flex justify-content-center”

>

<input

type=”text”

name=”sid”

id=”sid”

placeholder=”Enter Student ID”

className=”rounded p-2 m-2 mx-auto col-4"

/>

<input

type=”text”

name=”sname”

id=”sname”

placeholder=”Enter Student Name”

className=”rounded p-2 m-2 mx-auto col-4"

/>

<input

type=”text”

name=”scourse”

id=”scourse”

placeholder=”Enter Student Course”

className=”rounded p-2 m-2 mx-auto col-4"

/>

<div>

{state?.message ? (

<h3 className=”badge bg-danger”>{state?.message}</h3>

) : null}

</div>

<div className=”d-flex flex-row justify-content-center”>

<button

type=”submit”

name=”submit”

id=”submit”

value=”insert”

className=”btn btn-primary col-2 m-2"

>

{pending ? “Inserting …” : “Insert”}

</button>

<button

type=”submit”

name=”submit”

id=”submit”

value=”update”

className=” btn btn-primary col-2 m-2"

>

{pending ? “Updating …” : “Update”}

</button>

<button

type=”submit”

name=”submit”

id=”submit”

value=”delete”

className=” btn btn-primary col-2 m-2"

>

{pending ? “Deleting…” : “Delete”}

</button>

</div>

</form>

</div>

);

};

export default ModifyStudent;

In ModifyStudent component, I have use 2 hooks that are specially created by Next JS for Server Actions Components, first one is useFormStatus and useFormState, useFormStatus is use to check business for Server Actions Component, if Server Action Component is busy to perform some given task then it returns true in pending property otherwise return false. UseFormState hook is use to take 2 parameters, one is Server Actions Component as named “Mysqlserveraction” and second is initialState of message send by Server Actions to Client or Calling Component like ModifyStudent in my application case. This useFormState hook return two objects one is state object that receive message updates send by Server Actions and Second formAction object that pass to action element of HTML form.

Now, It’s time to understand code for Server Actions Component named “Mysqlserveraction”.

// Mysqlserveraction Component Code

“use server”;

import { revalidatePath } from “next/cache”;

import executeQuery from “./mysqldb”;

const Mysqlserveraction = async (prevState, formData) => {

const sid = formData.get(“sid”);

const sname = formData.get(“sname”);

const scourse = formData.get(“scourse”);

const bname = formData.get(“submit”);

if (bname === “insert”) {

if (sid!= “” && sname!= “” && scourse!= “”) {

const result = await executeQuery(“insert into student values(?,?,?)”, [

sid,

scourse,

sname,

]);

if (result.affectedRows) {

revalidatePath(“/CURDMySQL”);

return { message: “Record Inserted” };

} else {

revalidatePath(“/CURDMySQL”);

return { message: “Record not Inserted” };

}

} else {

revalidatePath(“/CURDMySQL”);

return { message: “Field can not be empty” };

}

} else if (bname === “update”) {

if (sid!= “” && sname!= “” && scourse!= “”) {

const result = await executeQuery(

“update student set sid=?, name=?, course=? where sid=?”,

[sid, sname, scourse, sid]

);

if (result.affectedRows) {

revalidatePath(“/CURDMySQL”);

return { message: “Record Updated” };

} else {

revalidatePath(“/CURDMySQL”);

return { message: “Record not Updated” };

}

} else {

revalidatePath(“/CURDMySQL”);

return { message: “Field can not be empty” };

}

} else if (bname === “delete”) {

if (sid!= “”) {

const result = await executeQuery(“delete from student where sid=?”, [

sid,

]);

if (result.affectedRows) {

revalidatePath(“/CURDMySQL”);

return { message: “Record Deleted” };

} else {

revalidatePath(“/CURDMySQL”);

return { message: “Record not Deleted” };

}

} else {

revalidatePath(“/CURDMySQL”);

return { message: “Student ID can not be empty” };

}

}

};

export default Mysqlserveraction;

In Mysqlserveraction Server Action component, we receive 2 arguments, first prevState that is same as we passed as initialState from ModifyStudent component, and second is formData, it is use to receive data from HTML form by ModifyStudent component. Next I am using executeQuery library or component that is specially design to make connectivity with MySQL database and perform all operation like reading, inserting, deleting or updating data in MySQL.

This is the code for executeQuery library or component to make MySQL connectivity.

//executeQuery component code

import mysql from “mysql2/promise”;

const executeQuery = async (query, data) => {

try {

var db = await mysql.createConnection({

host: “127.0.0.1”,

port: “3306”,

database: “studentmca”,

user: “root”,

password: “”,

});

const [result] = await db.execute(query, data);

db.end();

console.log(result);

return result;

} catch (error) {

console.log(error);

return error;

}

};

export default executeQuery;

One by one we perform all CURD operation using executeQuery component and display message back to user on ModifyStudent component state object like “Record inserted” or “Record not inserted” types.

At last, we have now code for DisplayStudentInfo is given as below:

//DisplayStudentInfo Component Code

“use server”;

import executeQuery from “./mysqldb”;

const DisplayStudentInfo = async () => {

const result = await executeQuery(“select * from student”, []);

return (

<div className=”container”>

<h3 className=”text-center”>Student Information</h3>

<table className=”text-center table table-dark”>

<thead>

<tr className=”table-warning”>

<th>Student ID</th>

<th>Student Name</th>

<th>Student Course</th>

</tr>

</thead>

<tbody>

{result.map((student) => (

<tr key={student.sid}>

<td>{student.sid}</td>

<td>{student.name}</td>

<td>{student.course}</td>

</tr>

))}

</tbody>

</table>

</div>

);

};

export default DisplayStudentInfo;

Output of above displayed code is shown in image given as below:

Image 1: Page.js Code for CURD Operations

It is not so simple to understand concept of Server Actions in Next JS, for completely understand it, you can watch best YouTube videos on Dr. Vipin Classes Channel specially designed or created for Build CRUD App with Next JS Server Actions and MySQL.

Link of Videos are:

1. Install and Setup MySQL in Next JS 14

2. NEXT JS MySQL CURD DISPLAY Operation

3. NEXT JS MySQL CURD INSERT Operation

4. NEXT JS MySQL CURD UPDATE Operation

5. NEXT JS MySQL CURD DELETE Operation

--

--

Dr. Vipin Kumar

Assoc. Prof. , DCA & Assoc. Head (SD), SDFS, at KIET, PhD (CS) My YouTube Channel: Dr. Vipin Classes (https://www.youtube.com/channel/UC-77P2ONqHrW7h5r6MAqgSQ)