diff --git a/pyproject.toml b/pyproject.toml
index b531488..2e0a644 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -55,6 +55,7 @@ ci = "https://github.com/machow/quartodoc/actions"
 
 [project.optional-dependencies]
 dev = [
+    "griffe-pydantic",
     "pytest<8.0.0",
     "pytest-cov",
     "jupyterlab",
diff --git a/quartodoc/_griffe_compat.py b/quartodoc/_griffe_compat.py
index af59b70..c931c70 100644
--- a/quartodoc/_griffe_compat.py
+++ b/quartodoc/_griffe_compat.py
@@ -10,6 +10,8 @@
 
     from griffe import Parser, parse, parse_numpy
     from griffe import AliasResolutionError
+
+    from griffe import load_extensions
 except ImportError:
     from griffe.loader import GriffeLoader
     from griffe.collections import ModulesCollection, LinesCollection
@@ -20,3 +22,5 @@
 
     from griffe.docstrings.parsers import Parser, parse
     from griffe.exceptions import AliasResolutionError
+
+    from griffe import load_extensions
diff --git a/quartodoc/autosummary.py b/quartodoc/autosummary.py
index c6bea4e..d7a6fde 100644
--- a/quartodoc/autosummary.py
+++ b/quartodoc/autosummary.py
@@ -8,8 +8,10 @@
 from ._griffe_compat import GriffeLoader, ModulesCollection, LinesCollection
 from ._griffe_compat import dataclasses as dc
 from ._griffe_compat import Parser, parse
+from ._griffe_compat import load_extensions
 
 from fnmatch import fnmatchcase
+from functools import partial
 from plum import dispatch  # noqa
 from pathlib import Path
 from types import ModuleType
@@ -24,7 +26,7 @@
 from .pandoc.components import Attr
 
 
-from typing import Any
+from typing import Any, Callable
 
 
 _log = logging.getLogger(__name__)
@@ -468,6 +470,9 @@ class Builder:
     items: list[layout.Item]
     """Documented items by this builder"""
 
+    _get_object: "Callable[[str], dc.Object | dc.Alias]"
+    """Internal function called to load each item."""
+
     def __init_subclass__(cls, **kwargs):
         super().__init_subclass__(**kwargs)
 
@@ -494,6 +499,7 @@ def __init__(
         dynamic: bool | None = None,
         parser="numpy",
         render_interlinks: bool = False,
+        griffe_extensions: "list[str | dict[str, dict[str, Any]]] | None" = None,
         _fast_inventory=False,
     ):
         self.layout = self.load_layout(
@@ -507,6 +513,9 @@ def __init__(
         self.sidebar = sidebar
         self.css = css
         self.parser = parser
+        self.griffe_extensions = (
+            load_extensions(*griffe_extensions) if griffe_extensions else None
+        )
 
         self.renderer = Renderer.from_config(renderer)
         if render_interlinks:
@@ -517,12 +526,26 @@ def __init__(
         if out_index is not None:
             self.out_index = out_index
 
+        self._get_object = partial(
+            get_object,
+            loader=self._create_griffe_loader(self.griffe_extensions),
+        )
         self.rewrite_all_pages = rewrite_all_pages
         self.source_dir = str(Path(source_dir).absolute()) if source_dir else None
         self.dynamic = dynamic
 
         self._fast_inventory = _fast_inventory
 
+    # TODO: annotation
+    def _create_griffe_loader(self, extensions):
+        return GriffeLoader(
+            docstring_parser=Parser(self.parser),
+            docstring_options=get_parser_defaults(self.parser),
+            modules_collection=ModulesCollection(),
+            lines_collection=LinesCollection(),
+            extensions=self.griffe_extensions,
+        )
+
     def load_layout(self, sections: dict, package: str, options=None):
         # TODO: currently returning the list of sections, to make work with
         # previous code. We should make Layout a first-class citizen of the
@@ -556,7 +579,13 @@ def build(self, filter: str = "*"):
         # shaping and collection ----
 
         _log.info("Generating blueprint.")
-        blueprint = blueprint(self.layout, dynamic=self.dynamic, parser=self.parser)
+        # TODO: set loader
+        blueprint = blueprint(
+            self.layout,
+            dynamic=self.dynamic,
+            parser=self.parser,
+            get_object=self._get_object,
+        )
 
         _log.info("Collecting pages and inventory items.")
         pages, self.items = collect(blueprint, base_dir=self.dir)
diff --git a/quartodoc/builder/blueprint.py b/quartodoc/builder/blueprint.py
index e796a89..5c118b5 100644
--- a/quartodoc/builder/blueprint.py
+++ b/quartodoc/builder/blueprint.py
@@ -35,7 +35,7 @@
 
 from .utils import PydanticTransformer, ctx_node, WorkaroundKeyError
 
-from typing import overload, TYPE_CHECKING
+from typing import Callable, overload, TYPE_CHECKING
 
 
 _log = logging.getLogger(__name__)
@@ -437,7 +437,11 @@ def blueprint(el: Auto, package: str) -> Doc:
 
 
 def blueprint(
-    el: _Base, package: str = None, dynamic: None | bool = None, parser="numpy"
+    el: _Base,
+    package: str = None,
+    dynamic: None | bool = None,
+    parser="numpy",
+    get_object: "None | Callable" = None,
 ) -> _Base:
     """Convert a configuration element to something that is ready to render.
 
@@ -449,6 +453,8 @@ def blueprint(
         A base package name. If specified, this is prepended to the names of any objects.
     dynamic:
         Whether to dynamically load objects. Defaults to using static analysis.
+    get_object:
+        The function to call to load the item. If specified, parser is ignored.
 
     Examples
     --------
@@ -463,7 +469,7 @@ def blueprint(
 
     """
 
-    trans = BlueprintTransformer(parser=parser)
+    trans = BlueprintTransformer(get_object=get_object, parser=parser)
 
     if package is not None:
         trans.crnt_package = package
diff --git a/quartodoc/tests/example_pydantic.py b/quartodoc/tests/example_pydantic.py
new file mode 100644
index 0000000..7abfa91
--- /dev/null
+++ b/quartodoc/tests/example_pydantic.py
@@ -0,0 +1,6 @@
+from pydantic import BaseModel
+
+
+class AModel(BaseModel):
+    a: int
+    """The a attribute."""
diff --git a/quartodoc/tests/test_builder.py b/quartodoc/tests/test_builder.py
index 932bc97..7c0b4ca 100644
--- a/quartodoc/tests/test_builder.py
+++ b/quartodoc/tests/test_builder.py
@@ -82,3 +82,22 @@ def test_builder_generate_sidebar(tmp_path, snapshot):
     d_sidebar = builder._generate_sidebar(bp)
 
     assert yaml.dump(d_sidebar) == snapshot
+
+
+def test_builder_griffe_extensions():
+    cfg = yaml.safe_load(
+        """
+    quartodoc:
+      package: quartodoc.tests.example_pydantic
+      griffe_extensions:
+        - griffe_pydantic:
+            schema: true
+    """
+    )
+    builder = Builder.from_quarto_config(cfg)
+    obj = builder._get_object("quartodoc.tests.example_pydantic.AModel")
+
+    # TODO: what to check here?
+    assert False
+
+    builder.build()