Next.js 15 "action is not a function" error during account creation

Hey everyone,

I’m currently diving into backend development using Next.js and have hit a snag that I’m hoping someone can help me with. I’ve spent the last 5 months getting to grips with HTML, CSS, and JavaScript, and I’m now venturing into the exciting (and sometimes confusing!) world of backend.

I’m following a YouTube tutorialthat was posted about two months ago, which seems to be using a similar stack to what I’m aiming for: Next.js 15, React 19, shadcn/ui for components, PostgreSQL for the database, Zustand for state management, Prisma as my ORM, and Lucia Auth for handling authentication.

The problem I’m encountering is during the account creation process. When I try to submit the signup form, I get the following error in my console:

TypeError: action is not a function

I’ve been trying to debug this for a while now, but as I’m still very new to backend concepts, I’m feeling a bit lost. From what I understand, this error usually means I’m trying to call something that isn’t actually a function. I suspect it might have something to do with how I’ve set up my form submission and the associated server-side logic (which I believe Next.js handles with Server Actions?).

Here’s a snippet of the relevant code from my SignUp component (it’s a Client Component using 'use client'):

JavaScript

'use client';

import React, { useActionState } from 'react';
import Form from 'next/form';
import { Loader2 } from 'lucide-react';

const initialState = {
  message: '',
};

type SignUpProps = {
  action: (prevState: any, formData: FormData) => Promise<{ message: string } | undefined>;
};

const SignUp = ({ action }: SignUpProps) => {
  const [state, formAction, isPending] = useActionState(action, initialState);

  return (
    // ... (rest of my JSX for the signup form)
    <Form action={formAction} className="...">
      {/* ... form fields ... */}
      <button type="submit" disabled={isPending}>
        {isPending ? <><Loader2 className="h-4 w-4 animate-spin" /> Creating Account...</> : 'Create Account'}
      </button>
    </Form>
    // ... (rest of my JSX)
  );
};

export default SignUp;

And here’s how I’m calling this component in my page.tsx file (I think this is where the “action” prop is being passed):

JavaScript

'use server';

import { getCurrentSession, registerUser, loginUser } from '@/actions/auth'; // Assuming my auth actions are here
import SignUp from '@/components/layout/auth/SignUp';
import { redirect } from 'next/navigation';
import React from 'react';
import zod from 'zod';

const SignUpSchema = zod.object({
  email: zod.string().email(),
  password: zod.string().min(5),
});

const SignUpPage = async () => {
  const { user } = await getCurrentSession();

  if (user) {
    return redirect('/');
  }

  const action = async (prevState: any, formData: FormData) => {
    const parsed = SignUpSchema.safeParse(Object.fromEntries(formData));
    if (!parsed.success) {
      return { message: "Invalid form data" };
    }

    const { email, password } = parsed.data;
    const { user, error } = await registerUser(email, password);
    if (error) {
      return { message: error };
    } else if (user) {
      await loginUser(email, password);
      return redirect("/");
    }
  };

  return <SignUp action={action} />;
};

export default SignUpPage;

My registerUser and loginUser functions are in a separate auth.ts file within my actions directory, and they both have "use server" at the top.

I’m really trying to understand how Server Actions and useActionState work together, but this error is throwing me off. Any guidance or pointers on what I might be doing wrong would be hugely appreciated!

Thanks in advance for your help.

Hi, I think that the problem is that action is defined inside your SignUpPage server component, but you’re passing it down to a client component (SignUp).

As far as I am aware, functions defined in server components aren’t serializable — so action is arriving as undefined on the client, causing your error message of TypeError: action is not a function.

To fix this you would need to define the action as a Server Action properly and pass it separately, or make SignUp itself a server component if you want it to directly use server actions.