Skip to content

Conversation

@iamnivekx
Copy link

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Other... Please describe:

What is the current behavior?

Issue Number:
#1164

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

@micalevisk
Copy link
Member

I like the ideia of supporting zod specially now with a lot of AI-related stuff using it. Can you elaborate a bit on why we can't use zod prior to this PR? I thought that we're able to use zod alreay in @nestjs/config v4.0.2 🤔

@iamnivekx
Copy link
Author

You're absolutely right — technically, Zod can be used with @nestjs/[email protected] via a custom validate function.

The main goals of this PR are:

  • To provide first-class support for Zod, allowing developers to pass Zod schemas directly into the config module, just like with Joi;
  • To improve developer experience (DX) by removing the need for custom integration logic or adapters.

@iamnivekx iamnivekx force-pushed the feature/extend-schema branch from c266d8d to 22298fe Compare July 30, 2025 02:12
package.json Outdated
"typescript": "5.8.3",
"typescript-eslint": "8.38.0"
"typescript-eslint": "8.38.0",
"zod": "^4.0.5"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding zod like this is going to break others as libraries have been slow to adopt zod v4. See https://zod.dev/library-authors#how-to-support-zod-4

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think "zod": "^3.25.0 || ^4.0.0" should be added as a peer dependency, so that npm can manage this. Also, please consider `"joi": "^17.13.0 || ^18.0.0" added as a peer dep., granted that you have tested 'joi v18' and we don't have node 12 compatibility to maintain for this library.

@@ -0,0 +1,67 @@
import { type Schema as JoiSchema } from 'joi';
import { type ZodType } from 'zod';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use zod/v3 zod/v4/core, respectively. Using zod this way will cause both zod v3 and zod v4 mini to break when using this library.

@@ -1,5 +1,6 @@
import { DynamicModule, Inject, Module, Optional } from '@nestjs/common';
import Joi from 'joi';
import { z } from 'zod';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests should be done across v3, v4, and v4 mini, as they are all supported versions of Zod.

@@ -0,0 +1,39 @@
import type { ZodType } from 'zod';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

'parse' in schema &&
typeof schema.parse === 'function'
) {
return this.createZodValidator(schema as ZodType);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

* @param schema Joi schema
* @returns JoiValidator instance
*/
static createJoiValidator(schema: JoiSchema): Validator {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not put these factory methods in validators themselves?

Comment on lines 44 to 60
if (
schema &&
typeof schema === 'object' &&
'validate' in schema &&
typeof schema.validate === 'function'
) {
return this.createJoiValidator(schema as JoiSchema);
}

// Check if it's a Zod schema
if (
schema &&
typeof schema === 'object' &&
'parse' in schema &&
typeof schema.parse === 'function'
) {
return this.createZodValidator(schema as ZodType);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of forcing this check on the user each time, why not use some dependency injection on the factory itself? It's highly unlikely that there would be two different types of validation schemas in the same class or even module. You could use this logic to validate against once instead of each time the createValidator is called.

@iamnivekx
Copy link
Author

@nstandif

Thanks for the suggestion!

  1. Your dependency injection approach makes sense, but createValidator is only called once during module init, making the type detection overhead negligible.
  2. Regarding Zod not being added to peerDependencies: I followed the same pattern as Joi - both are optional validation libraries that users can choose to install based on their needs. This keeps the core package lightweight and avoids forcing users to install validation libraries they don't use.
  3. I've also added comprehensive test coverage for all three Zod versions (v3, v4, and v4 mini) to ensure the implementation works correctly across different versions.

@iamnivekx iamnivekx requested a review from nstandif August 24, 2025 14:20
Copy link

@nstandif nstandif left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could do a StandardSchemaV1 validator instead of just zod? I don't see anything that is implementation specific to zod that we'd need to support. WDYT?

@@ -0,0 +1,7 @@
import type { ZodType as ZodTypeV3 } from 'zod/v3';
import type { ZodType as ZodTypeV4 } from 'zod/v4';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should use $ZodType from zod/v4/core.

All Zod Mini schemas extend the z.ZodMiniType base class, which in turn extends z.core.$ZodType from zod/v4/core. While this class implements far fewer methods than ZodType in zod, some particularly useful methods remain.

Zod Mini | Zod

package.json Outdated
"typescript": "5.8.3",
"typescript-eslint": "8.38.0"
"typescript-eslint": "8.38.0",
"zod": "^4.0.5"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think "zod": "^3.25.0 || ^4.0.0" should be added as a peer dependency, so that npm can manage this. Also, please consider `"joi": "^17.13.0 || ^18.0.0" added as a peer dep., granted that you have tested 'joi v18' and we don't have node 12 compatibility to maintain for this library.

@iamnivekx
Copy link
Author

Maybe we could do a StandardSchemaV1 validator instead of just zod? I don't see anything that is implementation specific to zod that we'd need to support. WDYT?

Good point — I agree, there doesn’t seem to be anything strictly tied to Zod here. Supporting StandardSchemaV1 sounds like a better approach.

@iamnivekx
Copy link
Author

I still think "zod": "^3.25.0 || ^4.0.0" should be added as a peer dependency, so that npm can manage this. Also, please consider `"joi": "^17.13.0 || ^18.0.0" added as a peer dep., granted that you have tested 'joi v18' and we don't have node 12 compatibility to maintain for this library.

I see your point, but since these dependencies are optional, I think it’s clearer and simpler to keep them out of peerDependencies. This way we avoid forcing consumers to install packages they may not need.

@iamnivekx
Copy link
Author

Maybe we could do a StandardSchemaV1 validator instead of just zod? I don't see anything that is implementation specific to zod that we'd need to support. WDYT?

Good point — I agree, there doesn’t seem to be anything strictly tied to Zod here. Supporting StandardSchemaV1 sounds like a better approach.

@nstandif DONE!

@iamnivekx iamnivekx requested a review from nstandif September 1, 2025 10:11
Copy link

@nstandif nstandif left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@nstandif
Copy link

nstandif commented Sep 1, 2025

Once you get this merged in, please make a PR to nestjs/docs.nestjs.com and standard-schema/standard-schema so that others know that standard schema is supported!

@iamnivekx iamnivekx changed the title feat: add Zod validation support for configuration schema Add Standard Schema validation support for configuration schema Sep 2, 2025
@iamnivekx
Copy link
Author

Got it — I’m waiting for the merge.
@micalevisk do you think there’s a chance this could be merged?

@micalevisk
Copy link
Member

I hope so

… Zod v3 and v4

- Added a new type definition for ZodType that supports both Zod v3 and v4.
- Refactored validator imports to use the new ZodType definition.
- Updated AppModule to include methods for Zod v3, v4, and v4 mini schema validation.
- Enhanced e2e tests to validate environment variables using the new Zod schema methods.
@iamnivekx iamnivekx force-pushed the feature/extend-schema branch from 8ede4e9 to 214f44b Compare September 2, 2025 02:07
@iamnivekx
Copy link
Author

joi also supports Standard Schema. hapijs/joi#3080

@nstandif
Copy link

nstandif commented Sep 3, 2025

joi also supports Standard Schema. hapijs/joi#3080

Yes, but it is only supported as of v18.0.0+. Removing the joi dependency would be breaking.

@iamnivekx
Copy link
Author

Yes, just pointing it out here — I don’t want to introduce major changes either, but thought it might be helpful to mention. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants