diff --git a/examples/python/dataclasses/trigger.py b/examples/python/dataclasses/trigger.py
index 135568ce7..ea1365233 100644
--- a/examples/python/dataclasses/trigger.py
+++ b/examples/python/dataclasses/trigger.py
@@ -1,3 +1,4 @@
from examples.dataclasses.worker import Input, say_hello
+# > Triggering a task
say_hello.run(input=Input(name="Hatchet"))
diff --git a/examples/python/dataclasses/worker.py b/examples/python/dataclasses/worker.py
index eeeeae8bf..f21ab34fe 100644
--- a/examples/python/dataclasses/worker.py
+++ b/examples/python/dataclasses/worker.py
@@ -4,6 +4,7 @@ from typing import Literal
from hatchet_sdk import Context, EmptyModel, Hatchet
+# > Dataclasses
@dataclass
class Input:
name: str
@@ -14,14 +15,19 @@ class Output:
message: str
+
+
hatchet = Hatchet(debug=True)
+# > Task using dataclasses
@hatchet.task(input_validator=Input)
def say_hello(input: Input, ctx: Context) -> Output:
return Output(message=f"Hello, {input.name}!")
+
+
def main() -> None:
worker = hatchet.worker("test-worker", workflows=[say_hello])
worker.start()
diff --git a/frontend/docs/pages/home/_meta.js b/frontend/docs/pages/home/_meta.js
index b20a0fcb0..d7384af78 100644
--- a/frontend/docs/pages/home/_meta.js
+++ b/frontend/docs/pages/home/_meta.js
@@ -130,6 +130,7 @@ export default {
pydantic: "Pydantic",
lifespans: "Lifespans",
"dependency-injection": "Dependency Injection",
+ dataclasses: "Dataclass Support",
blog: {
title: "Blog",
type: "page",
diff --git a/frontend/docs/pages/home/dataclasses.mdx b/frontend/docs/pages/home/dataclasses.mdx
new file mode 100644
index 000000000..68f5e3635
--- /dev/null
+++ b/frontend/docs/pages/home/dataclasses.mdx
@@ -0,0 +1,33 @@
+import { snippets } from "@/lib/generated/snippets";
+import { Snippet } from "@/components/code";
+import { Callout } from "nextra/components";
+
+# Dataclass Support
+
+Throughout the docs, we use Pydantic models in virtually all of our Python examples for validating task inputs and outputs. This is the recommended path, as it provides lots of safety guarantees as you're writing tasks. With that said, Hatchet also supports using `dataclasses` as both input and output types to tasks. **Dataclass support was added in SDK version 1.21.0.**
+
+
+ Dataclasses do not perform any type validation on instantiation like Pydantic
+ models do.
+
+
+### Usage
+
+To use a dataclass instead of a Pydantic model, you'll need to:
+
+1. Provide an `input_validator` as a parameter to your `workflow` or `task` (in the case of a standalone task with `hatchet.task`).
+2. Add return type hints for your `tasks`.
+
+### Example Usage
+
+`dataclass` validators work exactly like Pydantic models in Hatchet. First, you create the classes:
+
+
+
+And then you provide the classes to your workflow or task:
+
+
+
+And finally, triggering works the same as well - you just provide the dataclass instance as input:
+
+
diff --git a/sdks/python/examples/dataclasses/trigger.py b/sdks/python/examples/dataclasses/trigger.py
index 135568ce7..75a848536 100644
--- a/sdks/python/examples/dataclasses/trigger.py
+++ b/sdks/python/examples/dataclasses/trigger.py
@@ -1,3 +1,5 @@
from examples.dataclasses.worker import Input, say_hello
+# > Triggering a task
say_hello.run(input=Input(name="Hatchet"))
+# !!
diff --git a/sdks/python/examples/dataclasses/worker.py b/sdks/python/examples/dataclasses/worker.py
index eeeeae8bf..2290d0cc3 100644
--- a/sdks/python/examples/dataclasses/worker.py
+++ b/sdks/python/examples/dataclasses/worker.py
@@ -4,6 +4,7 @@ from typing import Literal
from hatchet_sdk import Context, EmptyModel, Hatchet
+# > Dataclasses
@dataclass
class Input:
name: str
@@ -14,14 +15,21 @@ class Output:
message: str
+# !!
+
+
hatchet = Hatchet(debug=True)
+# > Task using dataclasses
@hatchet.task(input_validator=Input)
def say_hello(input: Input, ctx: Context) -> Output:
return Output(message=f"Hello, {input.name}!")
+# !!
+
+
def main() -> None:
worker = hatchet.worker("test-worker", workflows=[say_hello])
worker.start()