Type Safe Server Actions with next-safe-action

6 min read

Why You Should Consider Using the next-safe-action Library

So, you're working on a Next.js project, right? Let me introduce you to a little helper called next-safe-action. This library provides an easy way to use Server Actions with type safety between server and client code!

How to Add next-safe-action to Your Next.js Project?

Step 1: Installation First things first, you need to get next-safe-action into your project. If you're on Next.js 14, just pop open your terminal and run:

pnpm add next-safe-action

But if you're still rocking Next.js 13, you'll want to stick with version 4 of the library:

pnpm add next-safe-action@v4

Step 2: Creating a zod schema

import * as z from "zod";

export const schema = z.object({
	name: z.string().min(3),
	content: z.string().min(10),
});

Step 3: Setting Up Server Action

Now, let's set up some server action, in this tutorial we're gonna use Supabase and create some simple logic to add blog post

"use server";

import { createSafeActionClient } from "next-safe-action";
import { supabase } from "@/services/supabase";
import { schema } from "@/lib/schemas";

export const action = createSafeActionClient();

export const addPost = action(schema, async (input) => {
	const { name, content } = input;

	const { data, error } = await supabase.from("post").insert({
		name,
		content,
	});

	if (error) {
		throw error;
	}
	return data;
});

Step 4: Implementing Form with react-hook-form

Let's create a simple form with a loading indicator and error handling thanks to next-safe-action

'use client'

export const Form = () => {
	const { execute, status, result } = useAction(addPost);
	const isLoading = status === "executing";
	const form = useForm<z.infer<typeof schema>>({
		resolver: zodResolver(schema),
		defaultValues: {
			name: "",
			content: "",
		},
	});

	const onSubmit = async (data: z.infer<typeof schema>) => {
		execute(data);
	};

	return (
		<form
			onSubmit={form.handleSubmit(onSubmit)}
			className="flex max-w-md flex-col gap-5 p-10"
		>
			<Input type="text" {...form.register("name")} placeholder="Name" />
			<Input type="text" {...form.register("content")} placeholder="Content" />
			<Button disabled={isLoading} type="submit">
				{isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
				Submit
			</Button>
			{result.serverError && <p>{result.serverError}</p>}
		</form>
	);
};

In this snippet, we're defining a server action and showing how you can easily call it from a component on the client side. It's a neat way to demonstrate the flexibility and power of the next-safe-action library in Next.js​​.

Psst... Check out official docs