Run Authenticated Server-side Mutations with Next.js Server Actions

Share this video with your friends

Send Tweet

Server Actions are a way to perform server-side mutations in the Next.js App Router. In this lesson, we create a <NewTweet /> component that renders a form for the user to enter a new tweet. This form is submitted to a Server Action, which writes this data to Supabase.

Additionally, we create a Server Action Supabase client and call the getUser function to fetch the currently signed in user.

Lastly, we write a Row Level Security (RLS) policy to enable the insert action for authenticated users.

Code Snippets

Posting form to Server Action

export default function NewTweet() {
  const addTweet = async () => {
    "use server";
  };

  return <form action={addTweet}>...</form>;
}

Create Supabase client in Server Action

const supabase = createServerActionClient<Database>({ cookies });

Get user from Supabase client

const {
  data: { user },
} = await supabase.auth.getUser();

Insert tweet with Supabase

await supabase.from("tweets").insert({...});

Resources

Xuefeng Wu
Xuefeng Wu
~ a year ago

The new added tweet is not displyed automatically unless I refresh the page

~ a year ago

The new added tweet is not displyed automatically unless I refresh the page

same for me

Brandon Perfetti
Brandon Perfetti
~ a year ago

Same here :/

~ 11 months ago

The missing piece is called read after write.

Read after write in server side action is tricky since there is no way for the form to know if the submission succeeded on the server side.

One fix, is creating a API endpoint [POST] app/api/new-tweet . Then make the new-page.tsx a client-side component. Upon successful submission, reset the form and reload the tweet page from the page.tsx.

Looking for other fixes.

~ 11 months ago

Here is much cleaner fix

diff --git a/app/components/new-tweet.tsx b/app/components/new-tweet.tsx index 220fb2e..ded818c 100644 --- a/app/components/new-tweet.tsx +++ b/app/components/new-tweet.tsx @@ -1,4 +1,5 @@ import { createServerActionClient } from "@supabase/auth-helpers-nextjs"; +import { revalidatePath } from "next/cache"; import { cookies } from "next/headers";

export default function NewTweet() { @@ -22,6 +23,7 @@ export default function NewTweet() {

     if (user) {
         await supabase.from('tweets').insert({title, user_id: user.id});
  •        revalidatePath('/');
       }

    }

~ 11 months ago
diff --git a/app/components/new-tweet.tsx b/app/components/new-tweet.tsx
index 220fb2e..ded818c 100644
--- a/app/components/new-tweet.tsx
+++ b/app/components/new-tweet.tsx
@@ -1,4 +1,5 @@
 import { createServerActionClient } from "@supabase/auth-helpers-nextjs";
+import { revalidatePath } from "next/cache";
 import { cookies } from "next/headers";

 export default function NewTweet() {
@@ -22,6 +23,7 @@ export default function NewTweet() {

         if (user) {
             await supabase.from('tweets').insert({title, user_id: user.id});
+            revalidatePath('/');
         }

     }