Safe Action Advanced

next-safe-action/skills/skills/safe-action-advanced

by next-safe-actiona2605bd2e84321245cba8f5718c144a6e4a5fa47No licenseListed Oct 9, 2026Updated Oct 9, 2026

Use when working with bind arguments, metadata schemas, framework errors (redirect/notFound/forbidden/unauthorized), type inference utilities (InferSafeActionFnInput/Result), or server-level action callbacks

AI-generated overview

Reference guide for advanced next-safe-action features: bind arguments, metadata, framework errors, type utilities and server callbacks.

What it does
This skill is a documentation-style reference for advanced features of the next-safe-action library. It explains how to pass extra arguments with .bind(), attach typed metadata for middleware, handle framework errors such as redirect, notFound, forbidden and unauthorized, and infer types from action functions and middleware. It also documents server-level action callbacks (onSuccess, onError, onSettled, onNavigation) and the throwServerError option, with code examples.
When to use it
Use it when writing or reviewing next-safe-action server actions that need bound arguments, typed metadata, framework-error handling, type inference utilities, or server-side callbacks. It is aimed at developers already working with this library rather than at general TypeScript questions.
Requirements
No scripts are shipped; it is instructions and reference documents only. It assumes the reader works in a project using the next-safe-action library with TypeScript and a Node.js server runtime.

next-safe-action Advanced Features

Overview

FeatureUse Case
Bind argumentsPass extra args to actions via .bind() (e.g., resource IDs)
MetadataAttach typed metadata to actions for use in middleware
Framework errorsHandle redirect, notFound, forbidden, unauthorized in actions
Type utilitiesInfer types from action functions and middleware

Server-Level Action Callbacks

The second argument to .action() accepts callbacks that run on the server (not client-side hooks):

ts
export const createPost = authActionClient  .inputSchema(schema)  .action(    async ({ parsedInput, ctx }) => {      const post = await db.post.create(parsedInput);      return post;    },    {      onSuccess: async ({ data, parsedInput, ctx, metadata, clientInput }) => {        // Runs on the server after successful execution        await invalidateCache("posts");      },      onError: async ({ error, metadata, ctx, clientInput, bindArgsClientInputs }) => {        // error: { serverError?, validationErrors? }        await logError(error);      },      onSettled: async ({ result }) => {        // Always runs        await recordMetrics(result);      },      onNavigation: async ({ navigationKind }) => {        // Runs when a framework error (redirect, notFound, etc.) occurs        console.log("Navigation:", navigationKind);      },    }  );

These are distinct from hook callbacks (useAction({ onSuccess })) — server callbacks run in the Node.js runtime, hook callbacks run in the browser.

throwServerError

Re-throw server errors instead of returning them as result.serverError:

ts
export const myAction = actionClient  .inputSchema(schema)  .action(serverCodeFn, {    throwServerError: true,    // The handled server error (return of handleServerError) is thrown  });

Don't confuse this with returnServerError(): throwServerError throws the handled error (post-handleServerError) instead of returning it, while returnServerError(payload) returns a typed expected error in result.serverError, bypassing handleServerError entirely (see the safe-action-client skill's error-handling doc).

Source and attribution

Source:next-safe-action/skillsinskills/safe-action-advancedat commita2605bd

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal