Next.js Discord

Discord Forum

Next.js and Supabase: Over 5 Seconds Waiting for Server Response in Server Action

Unanswered
Shih Tzu posted this in #help-forum
Open in Discord
Avatar
Shih TzuOP
I am trying to have a server action in Next.js which is called from a component. This server action is supposed to insert 25 records into a database. This process is taking over 5 seconds. Is this longer than expected? Are there any ways to speed it up?

33 Replies

Avatar
Shih TzuOP
<form action={updateQuiz}>
  <!-- input fields -->
</form>
I am currently in the process of pasting the code.
export async function updateQuiz(formData) {
    const cookieStore = cookies();const supabase = createServerComponentClient({cookies : () => cookieStore});const {data: {session}} = await supabase.auth.getSession();const user = session?.user;
    if (!user) {console.error("User is not authenticated - updateQuiz server action");return;}const id = formData.get('id');const name = formData.get('name');const category = formData.get('category');const description = formData.get('description');const { data: quizData, error: quizError } = await supabase.from('quiz').update({name, category, description}).match({id, user_id: user.id}).select();if (quizError) {return} if (quizData.length !== 1) {return} const quiz = quizData[0];
const { error: questionsError } = await supabase.from('question').delete().eq('quiz_id', quiz.id);
let questionNumber = 1; while (true) {if (formData.get(`q${questionNumber}`) === null){break} else 
{let questionText = formData.get(`q${questionNumber}`);let choice1 = formData.get(`q${questionNumber}c1`);let choice2 = formData.get(`q${questionNumber}c2`);let choice3 = formData.get(`q${questionNumber}c3`);let choice4 = formData.get(`q${questionNumber}c4`);const { data: questionData, error: questionError } = await supabase.from('question').insert([{ 'question_text': questionText, 'quiz_id': quiz.id, 'question_number': questionNumber }]).select(); const question = questionData[0]; const { data: choice1Data, error: choice1Error } = await supabase.from('choice').insert({ 'question_id': question.id, 'choice_text': choice1, 'is_correct': true }).select(); const { data: choice2Data, error: choice2Error } = await supabase.from('choice').insert({ 'question_id': question.id, 'choice_text': choice2, 'is_correct': false }).select()
const { data: choice3Data, error: choice3Error } = await supabase.from('choice').insert({ 'question_id': question.id, 'choice_text': choice3, 'is_correct': false }).select()
const { data: choice4Data, error: choice4Error } = await supabase.from('choice').insert({ 'question_id': question.id, 'choice_text': choice4, 'is_correct': false }).select()
        }questionNumber++}if (formData.get('next') === 'close') {revalidatePath(`/quizzes`); redirect('/quizzes')
    } else if (formData.get('next') === 'continue') {revalidatePath(`/quiz/${id}`)}}
I am not receiving any errors in the console. I could see how long it was taking in the network tab of dev tools.
To try to solve the issue, I have tried to re-run the code at a different time of day to see if it was a problem of supabase's end.
Avatar
Shih TzuOP
Increasing the number of questions to around 10 times out the request since it gets above 10 seconds which is too high for Vercel.
Avatar
Toyger
I think the problem that you run a lot of queries sequentially, and because of that additional network time added to that.
also queries is heavy.
you should to rewrite your data to bulk insert like
const { error } = await supabase
  .from('countries')
  .insert([
    { id: 1, name: 'Nepal' },
    { id: 1, name: 'Vietnam' },
  ])


and you should not return inserted data that you return with .select()
it add additional load to server.
you have all data in your script, you don't need to return it, you need only check if error happened on insert, and with bulk insert it will be only 1 query.
Avatar
Shih TzuOP
Ok, I will try this and see if the speed improves.
Avatar
Toyger
also maybe your supabase instance located too far from nextjs instance and it add time for network query additionally
Avatar
Shih TzuOP
Also, I have noticed that using server actions with Next.js has produced slower results compared to React + some sort of requests to backend.
 const addTask = async (newTask) => {
    if (newTask.title !== "") {
      if (user) {
        const tasksCollectionRef = collection(db, "tasks");
        try {
          const newTaskWithUser = { ...newTask, userId: user.uid};
          const docRef = await addDoc(tasksCollectionRef, newTaskWithUser);
          const taskId = docRef.id;
          const taskWithId = { ...newTask, id: taskId};
          const newTasks = [taskWithId, ...tasks];
          setTasks(newTasks);
        } catch (error) {}
      } else {
        const newTasks = [newTask, ...tasks];
        setTasks(newTasks);
        window.localStorage.setItem('tasks', JSON.stringify(newTasks));
      }
    }
  }
For example, the above is some jsx code from a different project. It was a React and Firebase to-do list app.
Here, the update was almost instantaneous on the page,
Avatar
Toyger
Also, I have noticed that using server actions with Next.js has produced slower results compared to React + some sort of requests to backend using fetch
iirc they are only some abstractions over it, so at the end they are same, it should be like microseconds difference that insignificant
Avatar
Shih TzuOP
In this code I am awaiting the addDoc() which I think is used to add the task to the firestore database.
Here is the network tab for my React + Firebase to-do app and you can see that it is very fast.
Image
Avatar
Toyger
but it's basically everything different, another db/provider/locations/amount of queries/etc...
so it's impossible to compare
Avatar
Shih TzuOP
In my form, I have two buttons. Each of them add a name and value to the form data. This enables me to perform a slightly different operation in the server action depending on which button is pressed. However, pressing the enter symbol after the input automatically assumes that I want to perform the action based on the name and value in the first button. Why is this the case? How can I disable submitting the form with the enter key?
Avatar
Toyger
tbh i didn't understand what you are trying to do in this example, if you are talking about form submission on Enter, and you have different use case, then it's better not to use form and use custom fields.
Avatar
Shih TzuOP
<form action={serverAction}>
    <button type="submit" name="next" value="close">Save and Close</button>
    <button type="submit" name="next" value="continue">Save and Continue Editing</button>
</form>
The enter key performs the same operation that the Save and Close button would. Why?
Why not the other button?

Separate question: is there a way to disable the enter key having any effect on form submission?
Avatar
Toyger
it browser default behaviour it get first "submit" element and perform it.
theoretically you can disable it by adding to form this:
onKeyPress={(e) => { e.key === 'Enter' && e.preventDefault(); }}
Avatar
Shih TzuOP
onKeyPress is deprecated
I have also noticed that the request is faster to process on localhost compared to in production. This could be because of the location of the serverless function on Vercel.
Avatar
Shih TzuOP
I do have another help forum post open. It has been a day so it's unlikely that anyone sees it, but the problem has still not been resolved. It is about props, server components, client components, useState and useEffect.
Avatar
Toyger
try onKeyDown
Avatar
Shih TzuOP
yes this works
Avatar
Toyger
of course on localhost you have almost 0 ping, but on vercel it's at least milliseconds
Avatar
Shih TzuOP
Vercel is 3 times slower though (3 seconds vs 9 seconds)
i'll do bulk inserts and see if that fixes the problem
Avatar
Toyger
I see that guy tried to help you can you quickly explain on what is current state of question.
Avatar
Shih TzuOP
ok, do you want to go to that one now?
Avatar
Toyger
ok