Skip to content

Next.js 13 Server Actions

Introduction

May 2023, Vercel announced that the App Router is recommended for production in the new version of Next.js v13.4, and it came with a lot of good features. In this article, we will focus on one of the best new features in the App Router: the Server Actions.

Server Actions vs Server Components

At first, you may think both Server Components and Server Actions are the same, but they are not. Server Components are featured in React 18 to render some components on the server side. On the other hand, Server Actions is a Next.js 13 feature that allows you to execute functions on the backend from the frontend.

Back to Web 1.0

Before Single Page Applications frameworks, we were using HTML forms for most things. All you had to do was add a directory to their action attribute, and it would push the data to the server with each input name. No state was required, no async and await, etc.

When Remix became open source last year, it introduced this idea again to the market. Its form actions would work even without JavaScript enabled in the browsers. It was mind-blowing.

Next.js Server Actions are similar, with a wider range of use cases. They added a lot to it so you don’t only use them on HTML forms, but also on buttons and client components.

How useful are Server Actions

As I said in the section above, the Server Actions are like Form Actions in Remix and also they work on both Server and Client in a way similar to tRPC or Telefunc. Think about it. Instead of creating an API endpoint and making a fetch request to it from the client side, you execute a function that’s already on the server from the client like any other JavaScript function.

Server Actions on the Server Side

To make this post more effective, I’ll build a simple counter component with Server Actions. It runs even if JavaScript is turned off.

First, create a new Next.js 13 App router project:

npx create-next-app@latest

Then, in the app/page.tsx, add a variable outside of the page component.

let count = 0;

export default function Home() {
  // ...
}

Then, add the Server Action, which is an async function with the “use server”; tag.

let count = 0;

export default function Home() {
  async function increment() {
    "use server";
    count++;
  }
  return (
    <div>
      <h1>Count</h1>
      <span>{count}</span>
      <form action={increment}>
        <button type="submit">Increment</button>
      </form>
    </div>
  )
}

After implementing the above, when you click on the increment button, you shouldn’t see the change until you refresh the page. You need to use revalidatePath to get a reactive state.

import { revalidatePath } from "next/cache";

let count = 0;

export default

 function Home() {
  async function increment() {
    "use server";
    count++;
    revalidatePath("/");
  }

  return (
    <div>
      <h1>Count</h1>
      <span>{count}</span>
      <form action={increment}>
        <button type="submit">Increment</button>
      </form>
    </div>
  )
}

Now you have a Counter that can run with zero JavaScript.

Server Actions on the Client Side

You can also use the Server Action on the client component (it will be more like tRPC and Telefunc) to trigger a function on the server from the client and get data.

But it will not work in the exact same way because in Next.js, each file has to be run on the server or the client. You can’t run the same file on both.

So we need to move the function to its own new file, and add the ”use server”; tag on the top of the file.

"use server";

export async function increment() {
  "use server";
  count++;
  revalidatePath("/");
}

We can import it from the client component, and use this server action there!

Conclusion

Server Actions are a great addition to Next.js, and it will make it easier to build full-stack applications that require a lot of work to be done in traditional frontend/backend ways like creating the API route, and then fetching it.

I hope you enjoyed this article, and if you have any questions or feedback, feel free to reach out to us.