# Data Validation in the Next.js Supabase Turbo kit

> Learn how to validate data in the Next.js Supabase Turbo kit.

*Canonical: https://makerkit.dev/docs/next-supabase-turbo/security/data-validation*

---

Data Validation is a crucial aspect of building secure applications. In this section, we will look at how to validate data in the Next.js Supabase Turbo kit.

{% sequence title="Steps to validate data" description="Learn how to validate data in the Next.js Supabase Turbo kit." %}

[What are we validating?](#what-are-we-validating)

[Using Zod to validate data](#using-zod-to-validate-data)

[Validating payload data to Server Side API](#validating-payload-data-to-server-side-api)

[Validating Cookies](#validating-cookies)

[Validating URL parameters](#validating-url-parameters)

{% /sequence %}

## What are we validating?

A general rule, is that all client-side provided data should be validated/sanitized. This includes:

- URL parameters
- Search params
- Form data
- Cookies
- Any data provided by the user

## Using Zod to validate data

The Next.js Supabase Turbo kit uses [Zod](https://zod.dev/) to validate data. You can use the `z` object to validate data in your application.

```ts
import * as z from "zod";

const userSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.string().email(),
});

// Validate the data
const validatedData = userSchema.parse(data);
```

## Validating payload data to Server Side API

We generally use two ways for sending data from a client to a server:

1. Server Actions
2. API Route Handlers

Let's look at how we can validate data for both of these cases.

### Server Actions: Using authActionClient

The `authActionClient` creates type-safe server actions with built-in Zod validation and authentication.

```ts
'use server';

import { authActionClient } from "@kit/next/safe-action";
import * as z from "zod";

const UserSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.string().email(),
});

export const createUserAction = authActionClient
  .inputSchema(UserSchema)
  .action(async ({ parsedInput, ctx: { user } }) => {
    // parsedInput is now validated against the UserSchema

    // do something with the validated data
  });
```

When you define an action using `authActionClient`, the `parsedInput` is validated against the `schema` automatically. The `ctx.user` provides the authenticated user.

### API Route Handlers: Using the "enhanceRouteHandler" utility

The `enhanceRouteHandler` hook is a utility hook that enhances Next.js API Route Handlers with Zod validation.

```ts
import { enhanceRouteHandler } from "@kit/next/routes";
import * as z from "zod";

const UserSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.string().email(),
});

export const POST = enhanceRouteHandler(async ({ body, user, request }) => {
  // body is now validated against the UserSchema
  // user is the authenticated user
  // request is the incoming request

  // do something with the validated data
}, {
    schema: UserSchema,
    auth: true,
});
```

Very similar to `authActionClient`, the `enhanceRouteHandler` utility enhances the handler function with Zod validation and authentication.

When you define an API route using `enhanceRouteHandler`, the `body` argument is validated against the `schema` option automatically. The `user` argument provides the authenticated user, and `request` is the incoming request object.

## Validating Cookies

Whenever you use a cookie in your application, you should validate the cookie data.

Let's assume you receive a cookie with the name `my-cookie`, and you expect it to be a number. You can validate the cookie data as follows:

```ts
import * as z from "zod";
import { cookies } from "next/headers";

const cookieStore = await cookies();

const cookie = z.coerce.number()
    .safeParse(cookieStore.get("my-cookie")?.value);

if (!cookie.success) {
  // handle the error or provide a default value
}
```

## Validating URL parameters

Whenever you receive a URL parameter, you should validate the parameter data. Let's assume you receive a URL parameter with the name `my-param`, and you expect it to be a number. You can validate the parameter data as follows:

```ts
interface PageProps {
    searchParams: Promise<{ myParam: string }>;
}

async function Page({ searchParams }: PageProps) {
    const params = await searchParams;

    const param = z.coerce.number()
        .safeParse(params.myParam);

    if (!param.success) {
        // handle the error or provide a default value
    }

    // render the page with the validated data
}
```

Going forward, remember to validate all data that you receive from the client, and never trust anything the client provides you with. Always have a default value ready to handle invalid data, which can prevent potential security issues or bugs in your application.

## Upgrading from v2

{% callout title="Differences with v2" %}
In v2, server actions used `enhanceAction` from `@kit/next/actions` and Zod was imported as `import { z } from 'zod'`. In v3, server actions use `authActionClient` from `@kit/next/safe-action` and Zod is imported as `import * as z from 'zod'`.

For the full migration guide, see [Upgrading from v2 to v3](/docs/next-supabase-turbo/installation/v3-migration).
{% /callout %}
