DEV Community

Cover image for Zod, A Population Schema Validation Library, Next.js
Tonny Kirwa
Tonny Kirwa

Posted on

Zod, A Population Schema Validation Library, Next.js

In Next.js, Zod is commonly used as a schema validation library to ensure data integrity and type safety for runtime data, such as form inputs, API responses, or environment variables. It is not a built-in part of Next.js but is often integrated into Next.js projects to handle validation and type inference in a robust, TypeScript-friendly way.

Schema Validation

  • Purpose: Zod allows you to define schemas to validate data structures, ensuring they conform to expected formats before processing them.
  • Use Cases:
    • Form Validation: Validate user inputs in forms (e.g., ensuring an email is valid or a password meets complexity requirements).
    • API Route Validation: Validate incoming request data in Next.js API routes or server actions.
    • Environment Variables: Validate environment variables to ensure they are present and correctly formatted before the app runs.

Example (Form Validation):

   import { z } from 'zod';

   // Define a schema for a user form
   const userSchema = z.object({
     name: z.string().min(2, 'Name must be at least 2 characters'),
     email: z.string().email('Invalid email address'),
     age: z.number().min(18, 'Must be at least 18'),
   });

   // In a Next.js API route or server action
   export async function POST(request: Request) {
     try {
       const data = await request.json();
       const validatedData = userSchema.parse(data); // Throws error if invalid
       // Process validated data
       return Response.json({ success: true, data: validatedData });
     } catch (error) {
       return Response.json({ error: 'Invalid data' }, { status: 400 });
     }
   }
Enter fullscreen mode Exit fullscreen mode

Type Safety with TypeScript

  • Zod integrates seamlessly with TypeScript by automatically inferring TypeScript types from schemas using z.infer.
  • This ensures that validated data is type-safe, reducing runtime errors and improving developer experience.

Example (Type Inference):

   import { z } from 'zod';

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

   // Infer TypeScript type from schema
   type User = z.infer<typeof userSchema>;

   // Use the inferred type
   const user: User = { name: 'John', email: 'john@example.com', age: 25 };
Enter fullscreen mode Exit fullscreen mode

Environment Variable Validation

  • In Next.js, environment variables are often defined in .env files. Zod can validate these variables to ensure they exist and have the correct format, especially in next.config.js or server-side code.

Example (Environment Variables):

   import { z } from 'zod';

   const envSchema = z.object({
     DATABASE_URL: z.string().url(),
     API_KEY: z.string().min(1),
   });

   const env = envSchema.parse({
     DATABASE_URL: process.env.DATABASE_URL,
     API_KEY: process.env.API_KEY,
   });

   // Use validated environment variables
   console.log(env.DATABASE_URL); // Safe access
Enter fullscreen mode Exit fullscreen mode

Integration with Next.js Features

  • Server Components and Server Actions: Zod can validate data in React Server Components or server actions, ensuring safe data handling on the server.
  • API Routes: Validate incoming JSON payloads in Next.js API routes to prevent invalid data from reaching your business logic.
  • Form Libraries: Zod is often used with libraries like react-hook-form or formik for client-side form validation in Next.js apps.

Example (with react-hook-form):

   import { useForm } from 'react-hook-form';
   import { zodResolver } from '@hookform/resolvers/zod';
   import { z } from 'zod';

   const schema = z.object({
     email: z.string().email('Invalid email'),
     password: z.string().min(6, 'Password too short'),
   });

   export default function LoginForm() {
     const { register, handleSubmit, formState: { errors } } = useForm({
       resolver: zodResolver(schema),
     });

     const onSubmit = (data: z.infer<typeof schema>) => {
       console.log('Validated data:', data);
     };

     return (
       <form onSubmit={handleSubmit(onSubmit)}>
         <input {...register('email')} />
         {errors.email && <p>{errors.email.message}</p>}
         <input {...register('password')} type="password" />
         {errors.password && <p>{errors.password.message}</p>}
         <button type="submit">Submit</button>
       </form>
     );
   }
Enter fullscreen mode Exit fullscreen mode

Error Handling

  • Zod provides detailed error messages when validation fails, which can be used to return meaningful feedback to users or log issues for debugging.
  • Example:

     try {
       userSchema.parse({ name: '', email: 'invalid', age: 'not-a-number' });
     } catch (error) {
       if (error instanceof z.ZodError) {
         console.log(error.errors); // Detailed validation errors
       }
     }
    

Why Use Zod in Next.js?

  • Type Safety: Combines runtime validation with TypeScript type inference.
  • Developer Experience: Clear, declarative schema definitions and detailed error messages.
  • Flexibility: Works across client, server, and API contexts in Next.js.
  • Ecosystem Compatibility: Integrates well with popular Next.js tools like react-hook-form, tRPC, or NextAuth.

Installation

To use Zod in a Next.js project:

npm install zod
# or
yarn add zod
Enter fullscreen mode Exit fullscreen mode

Conclusion

Zod’s role in Next.js is to provide robust data validation and type safety, making it easier to handle form inputs, API requests, and environment variables in a secure and maintainable way. It’s particularly valuable in TypeScript projects for ensuring consistency between runtime and compile-time types.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.