diff --git a/semantic_router/encoders/base.py b/semantic_router/encoders/base.py
index 2d4ad1f90f3cc4fab57ce6b8df4cbf838a4cb2de..c502d975ae7e12a6ccf60f26103077c01432478f 100644
--- a/semantic_router/encoders/base.py
+++ b/semantic_router/encoders/base.py
@@ -1,7 +1,7 @@
-from typing import Any, List, Optional
+from typing import Any, ClassVar, List, Optional
 
 import numpy as np
-from pydantic import BaseModel, Field, field_validator
+from pydantic import BaseModel, ConfigDict, Field, field_validator
 
 from semantic_router.route import Route
 from semantic_router.schema import SparseEmbedding
@@ -12,8 +12,7 @@ class DenseEncoder(BaseModel):
     score_threshold: Optional[float] = None
     type: str = Field(default="base")
 
-    class Config:
-        arbitrary_types_allowed = True
+    model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)
 
     @field_validator("score_threshold")
     def set_score_threshold(cls, v: float | None) -> float | None:
@@ -57,8 +56,7 @@ class SparseEncoder(BaseModel):
     name: str
     type: str = Field(default="base")
 
-    class Config:
-        arbitrary_types_allowed = True
+    model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)
 
     def __call__(self, docs: List[str]) -> List[SparseEmbedding]:
         """Sparsely encode a list of documents. Documents can be any type, but the encoder must
diff --git a/semantic_router/index/base.py b/semantic_router/index/base.py
index 3d6a3afad1ea3a7796df9ab7c2297afc314629f1..e7a25643dacd9482ffd0572d874dc12fff8e2ef6 100644
--- a/semantic_router/index/base.py
+++ b/semantic_router/index/base.py
@@ -2,10 +2,10 @@ import asyncio
 import json
 import time
 from datetime import datetime
-from typing import Any, Dict, List, Optional, Tuple, Union
+from typing import Any, ClassVar, Dict, List, Optional, Tuple, Union
 
 import numpy as np
-from pydantic import BaseModel
+from pydantic import BaseModel, ConfigDict
 
 from semantic_router.route import Route
 from semantic_router.schema import ConfigParameter, SparseEmbedding, Utterance
@@ -515,8 +515,7 @@ class BaseIndex(BaseModel):
         route_info = parse_route_info(metadata=metadata)
         return route_info  # type: ignore
 
-    class Config:
-        arbitrary_types_allowed = True
+    model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)
 
 
 def parse_route_info(metadata: List[Dict[str, Any]]) -> List[Tuple]:
diff --git a/semantic_router/index/local.py b/semantic_router/index/local.py
index 1c70daae29897142495bfe93c503d4ed39213bb1..b065d5ee16cfe427b9c01e4784b337b3ebd852a8 100644
--- a/semantic_router/index/local.py
+++ b/semantic_router/index/local.py
@@ -1,6 +1,7 @@
-from typing import Any, Dict, List, Optional, Tuple
+from typing import Any, ClassVar, Dict, List, Optional, Tuple
 
 import numpy as np
+from pydantic import ConfigDict
 
 from semantic_router.index.base import BaseIndex, IndexConfig
 from semantic_router.linear import similarity_matrix, top_scores
@@ -14,9 +15,8 @@ class LocalIndex(BaseIndex):
     def __init__(self):
         super().__init__()
 
-    class Config:
-        # Stop pydantic from complaining about Optional[np.ndarray]type hints.
-        arbitrary_types_allowed = True
+    # Stop pydantic from complaining about Optional[np.ndarray]type hints.
+    model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)
 
     def add(
         self,
diff --git a/semantic_router/index/postgres.py b/semantic_router/index/postgres.py
index dda6149e626ea1a2b9af7ee515a1e99c6b52b1d1..69b968f1a540a6b3bb270e02f1816a29e4b82bc1 100644
--- a/semantic_router/index/postgres.py
+++ b/semantic_router/index/postgres.py
@@ -1,10 +1,10 @@
 import os
 import uuid
 from enum import Enum
-from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
+from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Optional, Tuple, Union
 
 import numpy as np
-from pydantic import BaseModel, Field
+from pydantic import BaseModel, ConfigDict, Field
 
 from semantic_router.index.base import BaseIndex, IndexConfig
 from semantic_router.schema import ConfigParameter, Metric, SparseEmbedding
@@ -494,7 +494,5 @@ class PostgresIndex(BaseIndex):
                 return 0
             return count[0]
 
-    class Config:
-        """Configuration for the Pydantic BaseModel."""
-
-        arbitrary_types_allowed = True
+    """Configuration for the Pydantic BaseModel."""
+    model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)
diff --git a/semantic_router/llms/base.py b/semantic_router/llms/base.py
index a3e6c12232596da5bf49d60b3a6b25a8b6fcb70f..b9d5c82e9fa327977c13d5b141fb38e76efd1c83 100644
--- a/semantic_router/llms/base.py
+++ b/semantic_router/llms/base.py
@@ -1,7 +1,7 @@
 import json
-from typing import Any, Dict, List, Optional
+from typing import Any, ClassVar, Dict, List, Optional
 
-from pydantic import BaseModel
+from pydantic import BaseModel, ConfigDict
 
 from semantic_router.schema import Message
 from semantic_router.utils.logger import logger
@@ -18,8 +18,7 @@ class BaseLLM(BaseModel):
     temperature: Optional[float] = 0.0
     max_tokens: Optional[int] = None
 
-    class Config:
-        arbitrary_types_allowed = True
+    model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)
 
     def __init__(self, name: str, **kwargs):
         """Initialize the BaseLLM.
diff --git a/semantic_router/route.py b/semantic_router/route.py
index 4df7f1fcf70d9daca719d6ef8db58eeb8b5e632c..d194adb5d1d38f0fc87af41589f3ff95d69196dc 100644
--- a/semantic_router/route.py
+++ b/semantic_router/route.py
@@ -1,8 +1,8 @@
 import json
 import re
-from typing import Any, Callable, Dict, List, Optional, Union
+from typing import Any, Callable, ClassVar, Dict, List, Optional, Union
 
-from pydantic import BaseModel
+from pydantic import BaseModel, ConfigDict
 
 from semantic_router.llms import BaseLLM
 from semantic_router.schema import Message, RouteChoice
@@ -72,8 +72,7 @@ class Route(BaseModel):
     score_threshold: Optional[float] = None
     metadata: Optional[Dict[str, Any]] = {}
 
-    class Config:
-        arbitrary_types_allowed = True
+    model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)
 
     def __call__(self, query: Optional[str] = None) -> RouteChoice:
         """Call the route. If dynamic routes have been provided the query must have been
diff --git a/semantic_router/routers/base.py b/semantic_router/routers/base.py
index a6e27b40197f1a80e8d6e86e884fbcc42d23678a..1535f33f0cac9b19f3515b3fe2e240578ceececc 100644
--- a/semantic_router/routers/base.py
+++ b/semantic_router/routers/base.py
@@ -3,11 +3,11 @@ import importlib
 import json
 import os
 import random
-from typing import Any, Callable, Dict, List, Optional, Tuple, Union
+from typing import Any, Callable, ClassVar, Dict, List, Optional, Tuple, Union
 
 import numpy as np
 import yaml  # type: ignore
-from pydantic import BaseModel, Field
+from pydantic import BaseModel, ConfigDict, Field
 from tqdm.auto import tqdm
 from typing_extensions import deprecated
 
@@ -70,8 +70,7 @@ class RouterConfig:
 
     routes: List[Route] = Field(default_factory=list)
 
-    class Config:
-        arbitrary_types_allowed = True
+    model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)
 
     def __init__(
         self,
@@ -361,8 +360,7 @@ class BaseRouter(BaseModel):
     aggregation_method: Optional[Callable] = None
     auto_sync: Optional[str] = None
 
-    class Config:
-        arbitrary_types_allowed = True
+    model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)
 
     def __init__(
         self,
diff --git a/semantic_router/schema.py b/semantic_router/schema.py
index d5a68081169fd516ce68f8944002efeaffc8d809..d715dc877cf87feb69a53f39ad081096661bcbbf 100644
--- a/semantic_router/schema.py
+++ b/semantic_router/schema.py
@@ -2,11 +2,11 @@ import json
 from datetime import datetime, timezone
 from difflib import Differ
 from enum import Enum
-from typing import Any, Dict, List, Optional, Tuple, Union
+from typing import Any, ClassVar, Dict, List, Optional, Tuple, Union
 
 import numpy as np
 from aurelio_sdk.schema import SparseEmbedding as BM25SparseEmbedding
-from pydantic import BaseModel, Field
+from pydantic import BaseModel, ConfigDict, Field
 
 from semantic_router.utils.logger import logger
 
@@ -484,8 +484,7 @@ class SparseEmbedding(BaseModel):
 
     embedding: np.ndarray
 
-    class Config:
-        arbitrary_types_allowed = True
+    model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)
 
     @classmethod
     def from_compact_array(cls, array: np.ndarray):
diff --git a/semantic_router/utils/function_call.py b/semantic_router/utils/function_call.py
index 8fd450c01aa7154be27a5f8bc48c889218f7d77a..7462acdceb05d62a75dc7aab9b6e091bb0e50e6b 100644
--- a/semantic_router/utils/function_call.py
+++ b/semantic_router/utils/function_call.py
@@ -1,7 +1,7 @@
 import inspect
-from typing import Any, Callable, Dict, List, Optional, Union
+from typing import Any, Callable, ClassVar, Dict, List, Optional, Union
 
-from pydantic import BaseModel, Field
+from pydantic import BaseModel, ConfigDict, Field
 
 from semantic_router.llms import BaseLLM
 from semantic_router.schema import Message, RouteChoice
@@ -23,8 +23,7 @@ class Parameter(BaseModel):
     :type required: bool
     """
 
-    class Config:
-        arbitrary_types_allowed = True
+    model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)
 
     name: str = Field(description="The name of the parameter")
     description: Optional[str] = Field(