You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It looks like deepPartial was deprecated in 3.21.0. What should be used instead?
Also just to note that the documentation at https://zod.dev/?id=deeppartial doesn't make any mention of deepPartial being deprecated.
Reacted by Falk Meyer, Lars Grammel, Simon Lecoq, psychedelicious, Brandon Pereira, Chris Fougner, Amruth Pillai, aiber-jpw, Jan Gladines, Kasra Kyanzadeh and 134 more
Reacted by Pål Brattberg, Pranav, Maddison Cohodas, Kevin Clough, Trevor Pfizenmaier, Jonathan Yarbor, Mikko Ville Valjento, Mateusz Aliyev, Norah Maria, Pål Andreas Morholmen and 23 more
Bumping this. There doesn't seem to be any docs about why it was deprecated or what one should use instead.
Reacted by marc-eggers, Matt Barn, Rob Wells, Maksim, Pål Brattberg, Thiago Anselmo, Pranav, Simone Pizzamiglio, Mateusz Aliyev, Michael Scharf and 21 more
I've put together a solution to address the current issue: a fully type-safe utility that deeply makes any Zod schema partial, including nested objects, arrays, and all Zod types.
✅ Features
Full Type-Safety – Built with TypeScript from the ground up.
Supports All Zod Types – Handles complex, nested schemas correctly.
Zero Dependencies – Lightweight (~10KB).
Focused Utility – Does one thing: deeply partializes Zod schemas.
@antonio-ivanovski
We understand .deepPartial() was removed in v4 due to complexity/performance issues (we hit TS limits ourselves).
Same boat, complex indeed. We can all agree that .deepPartial leaves a bad taste in the mouth for good reasons.
Perhaps
A way to skip errors
Ex. if(error.code == 'required') skip — this way we can skip any specifics checks when parsing, and still get other errors.
Include a deepPartial-option for the .parse/.safeParse-method, that returns the .infer<T> as DeepPartial<T> (via 1st point)
Ex. User.parse(content, { deepPartial: true })
This way we can avoid the crazy type-gymnastics alongside the maintainence required to handle every ZodType — as well as increase the DX by explicitly stating this validation skip when parsing.
We use it for partial updates to existing (validated) documents as well.
Reacted by Luc Appelman, Jacob MacKenzie-Websdale, James Prevett, John, David, Daniel S. Valencia H. and Mehmet Kamil Morçay
The .deepPartial() method was deprecated in Zod 3 and removed in Zod 4 due to implementation issues and because it's considered an anti-pattern by the maintainers. There is no direct alternative or official workaround for deep partial schemas in Zod 4. If you need deep partial functionality, you'll need to write your own utility or manually construct the schema as needed. You can read the official rationale in the Zod v4 changelog and PR #4095.
The .partial() method is still available, but it only makes top-level properties optional and does not recurse into nested objects or arrays.
Given the high community interest and ongoing confusion, tagging @colinhacks for any further clarification or guidance on recommended patterns or future plans. If you have a specific use case, feel free to share it—sometimes the community can suggest workarounds.
If this answers your question, please close the issue.
This remains the most reliable approach. The zod-deep-partial npm package is purpose-built for making Zod schemas deeply partial. It has recently added support for more Zod features and now fully supports Zod v4. The project is actively maintained and will continue to receive updates. Contributions are very welcome!
Nah, this is still AI-generated slop (although it works slightly better now).
It still:
* has exponential complexity for non-tree shaped schemas 💣
* catastrophically fails due to missing proper handling for about 50% of Zod types 💀
Not even worth an in-depth review.
AI-generated? I’d be genuinely interested to know which AI model could generate a codebase like this.
Some functionality is still missing and will be added in future updates. Currently, the most important Zod schemas are supported, which should meet the needs of roughly 80% of users.
The approach you suggested is also a solid option, especially for advanced use cases. However, for many users it may be more complex than necessary. This solution aims to provide a simpler, more approachable option while remaining reliable and maintainable in the long term.
If it already works better than before, it will continue to improve over time.
Thank you for taking the time to share your feedback. Contributions are always welcome.
Reacted by Kemal, KazimirPodolski, Oshgnacknak and E. Alex Haywood
z.deepPartial(schema) available in both classic and mini.
z.mapOnSchema(schema, fn) exposed as the general traversal primitive — deepPartial is one line on top of it; deepStrict, deepReadonly, and user-defined rewrites become trivial follow-ups.
Dispatches on schema._zod.def.type, notinstanceof. Custom user-defined schema types pass through cleanly instead of being silently mishandled.
Full v4 def coverage (object/array/tuple+rest/record/map/set/union+discriminator/intersection/optional/nullable/default/prefault/nonoptional/catch/readonly/promise/success/pipe/function/lazy). Leaves left untouched.
Addressing the original concern
@colinhacks — the deprecation rationale in #2106 was about the brittle instanceof switch and the proliferation of edge cases. This PR specifically tries to not reintroduce that pattern: the def.type dispatch is open under user-defined types, the cycle behaviour is explicit (terminate or throw), and the primitive is exported so derived helpers don't each duplicate the logic. Happy to iterate on naming, scope, or close as wontfix if the design direction has changed.
Attribution
@jaens — the traversal pattern (mapOnSchema with RESOLVING sentinel) is adapted from your gist (Apache-2.0). The v4 implementation is a rewrite (def.type dispatch, core.clone, full v4 vocabulary coverage), and attribution is in the file header. Would value your review of the v4 port — especially whether the cycle handling matches what you intended.
On zod-deep-partial
@amirfarzamnia — the limitations you've already heard from @jaens (no cycle detection on lazy, half the advanced types not visited, exponential blowup on shared sub-schemas) were concrete bars this PR tried to clear. Both packages can coexist; this is a proposal for an in-tree solution that aims to be a drop-in for v3 users while structurally addressing #2106.
3807/3808 tests pass locally with 0 type errors (the one failure is an unrelated Windows-local recheck-jar env issue).
Reacted by Amir Farzamnia, andreasvh-conceto, Michael Tsibelman and John L. Armstrong IV
Update on #5928: expanded test suite to 40 cases (was 22) covering the edge cases @jaens flagged in earlier comments — discriminated unions (including the discriminator-becomes-optional collapse, now degraded to plain union to keep parsing correct), intersection, record / map / set, promise, pipe (both in/out recursed), wrapper composition (default + readonly + optional), 3-level nested objects, transform passthrough, shared sub-schema visited-once, unknown def.type passthrough. Recursive (lazy) cycle termination is verified. Full v4 test suite passes with 0 type errors.
Reacted by Michael Tsibelman, Nathan Kleyn and John L. Armstrong IV
@dokson I just came across this issue via the Github Gist and find the approach of the visit() pattern (used for deepPartial) very interesting. Would it also be possible to export this visit option publicly? I have some use cases where I need to define codec() recursively for a schema to make it ready for a data lakehouse.
Activity
foges commentedon Oct 17, 2023
Bumping this. There doesn't seem to be any docs about why it was deprecated or what one should use instead.
josesilveiraa07 commentedon Nov 3, 2023
Bumping this.
kodermax commentedon Nov 14, 2023
Bump
iway1 commentedon Nov 21, 2023
im gonna lock versions and just use
.deepPartial()I gueesspsychedelicious commentedon Nov 22, 2023
I noticed in #2106 the maintainer says:
However, that issue is about 9 months old and there doesn't appear to be any clarity/ETA on the outcome.
szulcus commentedon Dec 7, 2023
Bump
fmoessle commentedon Dec 12, 2023
bump
scharf commentedon Dec 22, 2023
Bump
wk-ouisense commentedon Jan 2, 2024
Bump 🤷♂️
caleygoff-invitae commentedon Jan 9, 2024
bump watching this -- locking versions until an alternative is available
broisnees commentedon Jan 19, 2024
any update regarding the
deepPartial, what should to use if this is deprecated?dannydi12 commentedon Jan 30, 2024
Also wondering what should be done here...
TKasperczyk commentedon Feb 22, 2024
How come this is still unresolved, and even completely unanswered?
cqone commentedon Feb 22, 2024
Bump
broisnees commentedon Feb 26, 2024
asdf
52 remaining items
amirfarzamnia commentedon May 19, 2025
🚀 Solution Available:
zod-deep-partialI've put together a solution to address the current issue: a fully type-safe utility that deeply makes any Zod schema
partial, including nested objects, arrays, and all Zod types.✅ Features
Get it on npm:
https://www.npmjs.com/package/zod-deep-partial
Source Code:
https://github.com/amirfarzamnia/zod-deep-partial
Documentation:
https://amirfarzamnia.github.io/zod-deep-partial/
It's simple to use: just import the function and apply it to your Zod schema.
Contributions and feedback are welcome!
jaens commentedon May 20, 2025
No it doesn't.
As already mentioned in a comment above, see https://gist.github.com/jaens/7e15ae1984bb338c86eb5e452dee3010 for the full list that needs to be handled (and something that actually does).
Refzlund commentedon May 31, 2025
Same boat, complex indeed. We can all agree that
.deepPartialleaves a bad taste in the mouth for good reasons.Perhaps
Ex.
if(error.code == 'required') skip— this way we can skip any specifics checks when parsing, and still get other errors.deepPartial-option for the.parse/.safeParse-method, that returns the.infer<T>asDeepPartial<T>(via 1st point)Ex.
User.parse(content, { deepPartial: true })This way we can avoid the crazy type-gymnastics alongside the maintainence required to handle every ZodType — as well as increase the DX by explicitly stating this validation skip when parsing.
We use it for partial updates to existing (validated) documents as well.
ahrjarrett commentedon Jul 15, 2025
deepPartialis available in@traversable/zod.It includes the circular detection @jaens mentioned, and has been fuzz tested to ensure the implementation works as expected.
Of course, use with care, this might be an anti-pattern, etc.
dosubot commentedon Jul 22, 2025
Hi @EricImpact! I'm Dosu and I’m helping the zod team.
I'm a bot trained on Zod's codebase and issues.
The
.deepPartial()method was deprecated in Zod 3 and removed in Zod 4 due to implementation issues and because it's considered an anti-pattern by the maintainers. There is no direct alternative or official workaround for deep partial schemas in Zod 4. If you need deep partial functionality, you'll need to write your own utility or manually construct the schema as needed. You can read the official rationale in the Zod v4 changelog and PR #4095.The
.partial()method is still available, but it only makes top-level properties optional and does not recurse into nested objects or arrays.Given the high community interest and ongoing confusion, tagging @colinhacks for any further clarification or guidance on recommended patterns or future plans. If you have a specific use case, feel free to share it—sometimes the community can suggest workarounds.
If this answers your question, please close the issue.
To reply, just mention @dosu.
Docs are dead. Just use Dosu.
amirfarzamnia commentedon Dec 15, 2025
This remains the most reliable approach. The
zod-deep-partialnpm package is purpose-built for making Zod schemas deeply partial. It has recently added support for more Zod features and now fully supports Zod v4. The project is actively maintained and will continue to receive updates. Contributions are very welcome!npm:
https://www.npmjs.com/package/zod-deep-partial
GitHub:
https://github.com/amirfarzamnia/zod-deep-partial
Documentation:
https://amirfarzamnia.github.io/zod-deep-partial/
jaens commentedon Dec 16, 2025
🤦
Nah, this is still AI-generated slop (although it works slightly better now).
It still:
Not even worth an in-depth review.
amirfarzamnia commentedon Dec 16, 2025
AI-generated? I’d be genuinely interested to know which AI model could generate a codebase like this.
Some functionality is still missing and will be added in future updates. Currently, the most important Zod schemas are supported, which should meet the needs of roughly 80% of users.
The approach you suggested is also a solid option, especially for advanced use cases. However, for many users it may be more complex than necessary. This solution aims to provide a simpler, more approachable option while remaining reliable and maintainable in the long term.
If it already works better than before, it will continue to improve over time.
Thank you for taking the time to share your feedback. Contributions are always welcome.
dokson commentedon May 1, 2026
Hi @PritamSangani — opened #5928 with a v4-native implementation. Tagging @jaens, @amirfarzamnia, and @colinhacks for design feedback.
What's there
z.deepPartial(schema)available in both classic and mini.z.mapOnSchema(schema, fn)exposed as the general traversal primitive —deepPartialis one line on top of it;deepStrict,deepReadonly, and user-defined rewrites become trivial follow-ups.Map<schema, RESOLVING|result>) — recursivelazyschemas terminate; shared sub-schemas visited once.schema._zod.def.type, notinstanceof. Custom user-defined schema types pass through cleanly instead of being silently mishandled.Addressing the original concern
@colinhacks — the deprecation rationale in #2106 was about the brittle
instanceofswitch and the proliferation of edge cases. This PR specifically tries to not reintroduce that pattern: thedef.typedispatch is open under user-defined types, the cycle behaviour is explicit (terminate or throw), and the primitive is exported so derived helpers don't each duplicate the logic. Happy to iterate on naming, scope, or close as wontfix if the design direction has changed.Attribution
@jaens — the traversal pattern (
mapOnSchemawithRESOLVINGsentinel) is adapted from your gist (Apache-2.0). The v4 implementation is a rewrite (def.type dispatch,core.clone, full v4 vocabulary coverage), and attribution is in the file header. Would value your review of the v4 port — especially whether the cycle handling matches what you intended.On
zod-deep-partial@amirfarzamnia — the limitations you've already heard from @jaens (no cycle detection on lazy, half the advanced types not visited, exponential blowup on shared sub-schemas) were concrete bars this PR tried to clear. Both packages can coexist; this is a proposal for an in-tree solution that aims to be a drop-in for v3 users while structurally addressing #2106.
3807/3808 tests pass locally with 0 type errors (the one failure is an unrelated Windows-local
recheck-jarenv issue).feat(v4): add `deepPartial` + `mapOnSchema` traversal primitive (coli…
dokson commentedon May 1, 2026
Update on #5928: expanded test suite to 40 cases (was 22) covering the edge cases @jaens flagged in earlier comments — discriminated unions (including the discriminator-becomes-optional collapse, now degraded to plain union to keep parsing correct), intersection, record / map / set, promise, pipe (both in/out recursed), wrapper composition (default + readonly + optional), 3-level nested objects, transform passthrough, shared sub-schema visited-once, unknown
def.typepassthrough. Recursive (lazy) cycle termination is verified. Full v4 test suite passes with 0 type errors.feat(v4): add `deepPartial` + `mapOnSchema` traversal primitive (coli…
feat(v4): add z.deepPartial and runtime z.input / z.output (#5928)
matzeeable commentedon Oct 12, 2026
@dokson I just came across this issue via the Github Gist and find the approach of the
visit()pattern (used fordeepPartial) very interesting. Would it also be possible to export this visit option publicly? I have some use cases where I need to definecodec()recursively for a schema to make it ready for a data lakehouse.