Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error: "Only async functions are allowed to be exported in a 'use server' file"

I am trying to use layout.tsx in the app directory of Next.js 13 to have a nav layout that is present on all the pages. I managed to make it so that when the user logs out/signs in, the navbar changes, but the issue is that I have to refresh the page (F5) to see the change on the navbar. I think this issue is related to the cache, and that's why I am trying to use export const dynamic = 'force-dynamic'.

I also added the client component to a server component because I thought that would be the issue, but it didn't solve the problem. I wanted to use export const dynamic = 'force-dynamic' to deal with the cache, but now I'm encountering an error that I can't seem to resolve. The error message I'm getting is:

Error

Only async functions are allowed to be exported in a "use server" file.

And here is the detailed error trace:

./app/components/ClientInsideServerLayout.tsx
Error: 
  x Only async functions are allowed to be exported in a "use server" file.
   ,-[C:\Users\zantl\OneDrive\Documentos\GitHub\sssss\gestion-gastos-supabase\app\components\ClientInsideServerLayout.tsx:2:1]
 2 | 
 3 | import { getSessionStatus } from "../ServerActions/isUserLoggedIn";
 4 | import ClientLayout from "./ClientLayout"
 5 | export const dynamic = 'force-dynamic'
   : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 6 | 
 7 | export async function ClientInsideServerLayout() {
 7 |     const isLoggedIn = await getSessionStatus();
   `----

Code

Here's the code for each relevant file that's causing the error:

File: ClientInsideServerLayout.tsx

'use server';

import { getSessionStatus } from "../ServerActions/isUserLoggedIn";
import ClientLayout from "./ClientLayout"
export const dynamic = 'force-dynamic'

export async function ClientInsideServerLayout() {
    const isLoggedIn = await getSessionStatus();
    return (
      <>
      <ClientLayout isLoggedIn={isLoggedIn}></ClientLayout>
      </>
    )
  }

File: ClientLayout.tsx

'use client'

import Link from 'next/link';
import { useRouter } from 'next/navigation'

export default function ClientLayout({ isLoggedIn }: { isLoggedIn: boolean }) {
  const router = useRouter();

  const signOut = async () => {
    try {
      const response = await fetch("http://localhost:3000/auth/sign-out", {
        method: "POST"
      });
  
      if (response.ok) {
        router.push("/")
        console.log('The resource has been permanently moved.');
      }     
    } catch (error: unknown) {
      console.error('An error occurred:', error);
    }
  };
  
  const logIn = () =>{
    router.push("/login")
  }
  
  
  
  
  return (
    <nav className="flex items-center justify-between flex-wrap bg-teal-500 p-6">
      <div className="flex items-center flex-shrink-0 text-white mr-6">
        {/* ... logo code ... */}
      </div>
      <div className="block lg:hidden">
        {/* ... button code ... */}
      </div>
      <div className="w-full block flex-grow lg:flex lg:items-center lg:w-auto">
        <div className="text-sm lg:flex-grow">
          <Link href="/ingresos" passHref>
            <span className="block mt-4 lg:inline-block lg:mt-0 text-teal-200 hover:text-white">
              Ingresos
            </span>
          </Link>
        </div>
        <div>
          {isLoggedIn ? (
            <button onClick={signOut} className="inline-block text-sm px-4 py-2 leading-none border rounded text-white border-white hover:border-transparent hover:text-teal-500 hover:bg-white lg:mt-0">Log Out</button>
          ) : (
            <>
              <button onClick={logIn} className="inline-block text-sm px-4 py-2 leading-none border rounded text-white border-white hover:border-transparent hover:text-teal-500 hover:bg-white lg:mt-0 mr-2">Log In</button>
              <button className="inline-block text-sm px-4 py-2 leading-none border rounded text-white border-white hover:border-transparent hover:text-teal-500 hover:bg-white lg:mt-0">Sign Up</button>
            </>
          )}
        </div>
      </div>
    </nav>
  );
}

Here's the code for the RootLayout that I'm using:

// Existing RootLayout code
'use server';
import './globals.css';
import { getSessionStatus } from './ServerActions/isUserLoggedIn';
import { ClientInsideServerLayout } from './components/ClientInsideServerLayout';

export default async function RootLayout({ children }: { children: React.ReactNode }) {
  const isLoggedIn = await getSessionStatus();

  return (
    <html lang="en">
      <body>
        <div>
          <ClientInsideServerLayout></ClientInsideServerLayout>
          {children}
        </div>
      </body>
    </html>
  );
}

Here's the directory structure for context:

app/
  auth/
    callback/
      route.ts
    sign-in/
      route.ts
    sign-out/
      route.ts
    sign-up/
      route.ts
  components/
    ClientInsideServerLayout.tsx
    ClientLayout.tsx
    Login.tsx
    tablaIngresos.tsx
  ingresos/
    page.tsx
  login/
    messages.tsx
    page.tsx
  ServerActions/
    isUserLoggedIn.ts
  _examples/
    client-component/
      page.tsx
    route-handler/
      route.ts
    server-action/
      page.tsx
    server-component/
      page.tsx
  auth-form.tsx
  favicon.ico
  globals.css
  layout.tsx
  page.tsx
components/
  LogoutButton.tsx
  NextJsLogo.tsx
  SupabaseLogo.tsx
types/
  supabase.ts
.env.local
.gitignore
middleware.ts
next-env.d.ts
next.config.js
package-lock.json
package.json
postcss.config.js
README.md
tailwind.config.js
tsconfig.json

Question

Can someone explain why this error is happening, and how can I fix it while keeping the layout update functionality when clicking the log-out button? I want to achieve this without having to refresh the page.

Any insights or suggestions would be greatly appreciated! Thank you!

like image 299
Vladimirzb Avatar asked Jan 23 '26 06:01

Vladimirzb


1 Answers

I had a similar issue in next 14 where I was using an index.ts file to centralize my exports of server actions. The issue was that I needed to remove the 'use server' from the index.ts file itself.

WRONG:

'use server'

/**
 * Simplify and centralize server action exports
 */
export { signIn } from "./signIn";
export { signOut } from "./signOut";
export { createComment } from "./createComment";
export { createPost } from "./createPost";
export { createTopic } from "./createTopic";

CORRECT: Remove use server from top of file.

/**
 * Simplify and centralize server action exports
 */
export { signIn } from "./signIn";
export { signOut } from "./signOut";
export { createComment } from "./createComment";
export { createPost } from "./createPost";
export { createTopic } from "./createTopic";

Example of createComment server action

"use server";

export async function createComment() {}

Properly exporting an async function from it with use server at the top of each individual server action file.

Hope this helps someone.

like image 175
CodeConnoisseur Avatar answered Jan 25 '26 21:01

CodeConnoisseur



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!