--- status: "published" label: "Writing data to Database" order: 5 title: "Learn how to write data to the Supabase database in your Next.js app" description: "In this page we learn how to write data to the Supabase database in your Next.js app" --- In this page, we will learn how to write data to the Supabase database in your Next.js app. {% sequence title="How to write data to the Supabase database" description="In this page we learn how to write data to the Supabase database in your Next.js app" %} [Writing a Server Action to Add a Task](#writing-a-server-action-to-add-a-task) [Defining a Schema for the Task](#defining-a-schema-for-the-task) [Writing the Server Action to Add a Task](#writing-the-server-action-to-add-a-task) [Creating a Form to Add a Task](#creating-a-form-to-add-a-task) [Using a Dialog component to display the form](#using-a-dialog-component-to-display-the-form) {% /sequence %} ## Writing a Server Action to Add a Task Server Actions are defined by adding `use server` at the top of the function or file. When we define a function as a Server Action, it will be executed on the server-side. This is useful for various reasons: 1. By using Server Actions, we can revalidate data fetched through Server Components 2. We can execute server side code just by calling the function from the client side In this example, we will write a Server Action to add a task to the database. ### Defining a Schema for the Task We use Zod to validate the data that is passed to the Server Action. This ensures that the data is in the correct format before it is written to the database. The convention in Makerkit is to define the schema in a separate file and import it where needed. We use the convention `file.schema.ts` to define the schema. ```tsx import * as z from 'zod'; export const WriteTaskSchema = z.object({ title: z.string().min(1), description: z.string().nullable(), }); ``` ### Writing the Server Action to Add a Task In this example, we write a Server Action to add a task to the database. We use the `revalidatePath` function to revalidate the `/home` page after the task is added. ```tsx 'use server'; import { revalidatePath } from 'next/cache'; import { getLogger } from '@kit/shared/logger'; import { getSupabaseServerClient } from '@kit/supabase/server-client'; import { authActionClient } from '@kit/next/safe-action'; import { WriteTaskSchema } from '~/home/(user)/_lib/schema/write-task.schema'; export const addTaskAction = authActionClient .inputSchema(WriteTaskSchema) .action(async ({ parsedInput: task, ctx: { user } }) => { const logger = await getLogger(); const client = getSupabaseServerClient(); logger.info(task, `Adding task...`); const { data, error } = await client .from('tasks') .insert({ ...task, account_id: user.id }); if (error) { logger.error(error, `Failed to add task`); throw new Error(`Failed to add task`); } logger.info(data, `Task added successfully`); revalidatePath('/home', 'page'); }); ``` Let's focus on this bit for a second: ```tsx const { data, error } = await client .from('tasks') .insert({ ...task, account_id: auth.data.id }); ``` Do you see the `account_id` field? This is a foreign key that links the task to the user who created it. This is a common pattern in database design. Now that we have written the Server Action to add a task, we can call this function from the client side. But we need a form, which we define in the next section. ### Creating a Form to Add a Task We create a form to add a task. The form is a React component that accepts a `SubmitButton` prop and an `onSubmit` prop. ```tsx import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; import * as z from 'zod'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from '@kit/ui/form'; import { Input } from '@kit/ui/input'; import { Textarea } from '@kit/ui/textarea'; import { Trans } from '@kit/ui/trans'; import { WriteTaskSchema } from '../_lib/schema/write-task.schema'; export function TaskForm(props: { task?: z.infer; onSubmit: (task: z.infer) => void; SubmitButton: React.ComponentType; }) { const form = useForm({ resolver: zodResolver(WriteTaskSchema), defaultValues: props.task, }); return (
{ return ( ); }} name={'title'} /> { return (