Type Safe Server Actions with next-safe-action
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!
- Type Safety
- Input Validation
- Server Error Handling
- Optimistic Updates
- Ease of Use
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