Migration from v6 to v7
What's new?
Well, pretty much everything. Version 7 now works using methods; you might be familiar with this design if you have worked with tRPC or Kysely. A complete rewrite of the library in this direction was needed to vastly improve next-safe-action's APIs, and ensure that future versions will not break them (unless React/Next.js APIs change under the hood). The new design is much more resilient, powerful and flexible.
TL;DR
But please still read this migration guide carefully before upgrading to v7.
Assuming you're using Zod, in previous versions, you'd define an auth action client and then an action like this:
import { createSafeActionClient } from "next-safe-action";
import { cookies } from "next/headers";
// Base client
export const baseActionClient = createSafeActionClient();
// Auth client
export const authActionClient = createSafeActionClient({
async middleware(parsedInput) {
const session = cookies().get("session")?.value;
if (!session) {
throw new Error("Session not found!");
}
const userId = await getUserIdFromSessionId(session);
if (!userId) {
throw new Error("Session is not valid!");
}
return { userId };
},
});
"use server";
import { authActionClient } from "@/lib/safe-action";
import { z } from "zod";
export const editProfile = authActionClient(z.object({ username: z.string() }), async ({ username }, { ctx: { userId } }) => {
await saveNewUsernameInDb(userId, username);
return {
updated: true,
}
})
The same behavior can be achieved in v7 with the following refectored code:
import { createSafeActionClient } from "next-safe-action";
import { cookies } from "next/headers";
// Base client
export const actionClient = createSafeActionClient();
// Auth client
export const authActionClient = actionClient.use(async ({ next, ctx }) => {
const session = cookies().get("session")?.value;
if (!session) {
throw new Error("Session not found!");
}
const userId = await getUserIdFromSessionId(session);
if (!userId) {
throw new Error("Session is not valid!");
}
return next({ ctx: { userId } });
});
"use server";
import { authActionClient } from "@/lib/safe-action";
import { z } from "zod";
export const editProfile = authActionClient
.schema(z.object({ username: z.string() }))
.action(async ({ parsedInput: { username }, ctx: { userId } }) => {
await saveNewusernameInDb(userId, username)
return {
updated: true,
}
});
New features
Allow setting validation errors in action server code function
Sometimes it's useful to set custom validation errors in the action server code function, for example when the user wants to log in, but there was a problem with the email or password fields. next-safe-action v7 introduces a new function called returnValidationErrors
that allows you to do that.
Support schema nested objects validation
Before v7, next-safe-action allowed you to define schemas with nested objects, but validation errors were not correctly set for nested fields. Version 7 of the library changes the returned errors to be an object with nested fields, that emulates Zod's format
method.
Support middleware chaining
This is a core change in next-safe-action v7. In previous versions, you could define just one "monolithic" middleware at the instance level. So, the previous workflow was to define multiple safe action clients, each one with its own middleware.
With version 7, you can chain multiple middleware functions using the use
method, both at the instance level and at the action level. This is explained in detail in the middleware page of the documentation. The new design is much more flexible and powerful, allowing you to do things that just couldn't be done before, such as extending context, logging action execution, integrating with third party systems for error reporting, etc.
Generic type for serverError
The serverError
property of the action result object is now of generic type. By default it's a string
with a default value of "Something went wrong while executing the operation.". You can customize error value and type using the handleReturnedServerError
initialization function, just like pre-v7. Basically, what you return from that function is what serverError
will be on the client.
Support binding additional arguments
Next.js allows you to pass additional arguments to the action using JavaScript bind
method. This approach has the advantage of supporting progressive enhancement.
next-safe-action v7 supports bind arguments via the bindArgsSchemas
method.