⚡ createAction()
Automatically initializes the server client with cookies and returns a type-safe { data, error } object for all your Server Actions.
If you are using Server Actions ("use server";) heavily in Next.js, handling Try/Catch blocks rapidly becomes a massive chore. createAction abstracts this problem away entirely by catching thrown errors and cleanly serializing them.
Basic Usage
Wrap your asynchronous functions using createAction:
// app/actions.ts
"use server";
import { createAction } from "next-supa-utils/server";
export const getProfile = createAction(async (supabase, userId: string) => {
const { data, error } = await supabase
.from("profiles")
.select()
.eq("id", userId)
.single();
if (error) throw error; // Safe to throw. It will be serialized!
return data;
});
Using it inside a Client Component remains fully type-safe and consistent:
// Usage
const result = await getProfile("123");
if (result.error) {
// result.error is a parsed SupaError (exposes message, code, etc)
console.error(result.error.message);
return;
}
// result.data is correctly inferred as your query payload type!
console.log(result.data);
How It Works Under The Hood
Signature:
function createAction<TArgs extends unknown[], TResult>(
fn: (supabase: SupabaseClient, ...args: TArgs) => Promise<TResult>
): (...args: TArgs) => Promise<ActionResponse<TResult>>
- Client Provisioning:
createActiongrabscookies()fromnext/headersand creates an ephemeral, secure Supabase browser client, inserting it as the first argument of your callback. - Execution Block: It runs your supplied function.
- Implicit Error Catching: Because it is enclosed in a try/catch, ANY thrown error inside the function is normalized into
SupaError. - Standardized Responses: It promises to return a discriminated union pattern heavily inspired by Supabase's JS SDK itself:
// Success Response:
{ data: TResult, error: null }
// Failure Response:
{ data: null, error: SupaError } // Next.js understands and safely serializes this over network boundaries.