Skip to main content

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:

action-client-v6.ts
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 };
},
});
action-v6.ts
"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:

action-client-v7.ts
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 } });
});
action-v7.ts
"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.

Support custom validation errors format

As already said above, by default version 7 now returns validation errors in the same format of the Zod's format method.

This is customizable using the formatValidationErrors/formatBindArgsValidationErrors optional functions in schema/bindArgsSchemas methods. Check out this page for more information. For instance, if you need to work with flattened errors (just like pre-v7), next-safe-action conveniently provides two functions to do that: flattenValidationErrors and flattenBindArgsValidationErrors.

Allow omitting schema argument in schema method

In previous versions, you always had to pass a schema for your action, even if it was empty (in the case of Zod, z.void()). Starting from v7, you can omit the schema argument in the schema method.

Allow calling action method without schema

Sometimes it's not necessary to define an action with input. In this case, you can omit the schema method and use directly the action/stateAction method.

Support stateful actions using React useActionState hook

React added a hook called useActionState that replaces the previous useFormState hook and improves it. next-safe-action v7 uses it under the hood in the exported useStateAction hook, that keeps track of the state of the action execution.

Note that this hook expects as argument actions defined using the stateAction method, and not the usual action method. Find more information about these two methods here.

Return input from hooks

Sometimes it's useful to access the input passed to an action when using hooks. Starting from version 7, input property is returned from hooks.

Return shorthand statuses from hooks

Starting from version 7, isIdle, isExecuting, hasSucceeded and hasErrored are returned from hooks, in addition to the status property. This is the same behavior of next-safe-action pre-v4 and very similar to the TanStack Query API.

Refactors

serverCodeFn signature

Previously, serverCodeFn had two arguments: parsedInput and ctx. Now, it only has one argument, which is an object that contains parsedInput and ctx, and other useful properties. In the case of stateAction method, serverCodeFn also has an additional argument, which is an object that contains the previous result of the action. Find more information about serverCodeFn here.

useOptimisticAction signature

The function signature for useOptimisticAction has been updated to be much more clear and readable. Before, you had to pass currentState and updateFn as the second and third argument of the hook. Now, the first argument is the safe action, and additional required and optional properties are placed inside the second argument of the hook, which is an object.

Other than that, now currentState is unlinked from the safe action's return value. The action purpose in optimistic state updates is just to make mutations of data. Then, the fresh data is refetched from the parent Server Component, so it didn't make sense to lock the type of currentState to the action's return type. This is explained in detail here and here.

Find more information about the updated useOptimisticAction hook here.

Hook callbacks arguments

Previously, there were multiple arguments in hook callbacks. Now, metadata is passed inside a single object that is the first argument of each function. Find more information about the updated callbacks here.

Action metadata

In version 6, you could pass metadata to actions via the third argument of the safe action function, after serverCodeFn. In version 7, there's a dedicated metadata method that lets you define useful data for the action execution. This data can then be accessed in middleware functions and serverCodeFn. Find more information about the metadata method here.

Internal changes

TypeSchema update

TypeSchema was updated to v0.13, so now, if you want to use a validation library other than Zod, you also need to install the related TypeSchema adapter.

Requirements

next-safe-action version 7 requires Next.js 14.3.0 and React 19 or later to work.

What about v6?

You can still keep using version 6 and eventually upgrade to version 7. Note that version 6 is frozen and no new features will be released in the future for it. v6 documentation can still be found here.