diff --git a/docs/en/docs/advanced/settings.md b/docs/en/docs/advanced/settings.md
index 60ec9c92c..7bf147031 100644
--- a/docs/en/docs/advanced/settings.md
+++ b/docs/en/docs/advanced/settings.md
@@ -125,7 +125,34 @@ That means that any value read in Python from an environment variable will be a
## Pydantic `Settings`
-Fortunately, Pydantic provides a great utility to handle these settings coming from environment variables with Pydantic: Settings management.
+Fortunately, Pydantic provides a great utility to handle these settings coming from environment variables with Pydantic: Settings management.
+
+### Install `pydantic-settings`
+
+First, install the `pydantic-settings` package:
+
+
+
+```console
+$ pip install pydantic-settings
+---> 100%
+```
+
+
+
+It also comes included when you install the `all` extras with:
+
+
+
+```console
+$ pip install "fastapi[all]"
+---> 100%
+```
+
+
+
+!!! info
+ In Pydantic v1 it came included with the main package. Now it is distributed as this independent package so that you can choose to install it or not if you don't need that functionality.
### Create the `Settings` object
@@ -135,9 +162,20 @@ The same way as with Pydantic models, you declare class attributes with type ann
You can use all the same validation features and tools you use for Pydantic models, like different data types and additional validations with `Field()`.
-```Python hl_lines="2 5-8 11"
-{!../../../docs_src/settings/tutorial001.py!}
-```
+=== "Pydantic v2"
+
+ ```Python hl_lines="2 5-8 11"
+ {!> ../../../docs_src/settings/tutorial001.py!}
+ ```
+
+=== "Pydantic v1"
+
+ !!! info
+ In Pydantic v1 you would import `BaseSettings` directly from `pydantic` instead of from `pydantic_settings`.
+
+ ```Python hl_lines="2 5-8 11"
+ {!> ../../../docs_src/settings/tutorial001_pv1.py!}
+ ```
!!! tip
If you want something quick to copy and paste, don't use this example, use the last one below.
diff --git a/docs_src/conditional_openapi/tutorial001.py b/docs_src/conditional_openapi/tutorial001.py
index 717e723e8..eedb0d274 100644
--- a/docs_src/conditional_openapi/tutorial001.py
+++ b/docs_src/conditional_openapi/tutorial001.py
@@ -1,5 +1,5 @@
from fastapi import FastAPI
-from pydantic import BaseSettings
+from pydantic_settings import BaseSettings
class Settings(BaseSettings):
diff --git a/docs_src/settings/app01/config.py b/docs_src/settings/app01/config.py
index defede9db..b31b8811d 100644
--- a/docs_src/settings/app01/config.py
+++ b/docs_src/settings/app01/config.py
@@ -1,4 +1,4 @@
-from pydantic import BaseSettings
+from pydantic_settings import BaseSettings
class Settings(BaseSettings):
diff --git a/docs_src/settings/app02/config.py b/docs_src/settings/app02/config.py
index 9a7829135..e17b5035d 100644
--- a/docs_src/settings/app02/config.py
+++ b/docs_src/settings/app02/config.py
@@ -1,4 +1,4 @@
-from pydantic import BaseSettings
+from pydantic_settings import BaseSettings
class Settings(BaseSettings):
diff --git a/docs_src/settings/app02_an/config.py b/docs_src/settings/app02_an/config.py
index 9a7829135..e17b5035d 100644
--- a/docs_src/settings/app02_an/config.py
+++ b/docs_src/settings/app02_an/config.py
@@ -1,4 +1,4 @@
-from pydantic import BaseSettings
+from pydantic_settings import BaseSettings
class Settings(BaseSettings):
diff --git a/docs_src/settings/app02_an_py39/config.py b/docs_src/settings/app02_an_py39/config.py
index 9a7829135..e17b5035d 100644
--- a/docs_src/settings/app02_an_py39/config.py
+++ b/docs_src/settings/app02_an_py39/config.py
@@ -1,4 +1,4 @@
-from pydantic import BaseSettings
+from pydantic_settings import BaseSettings
class Settings(BaseSettings):
diff --git a/docs_src/settings/app03/config.py b/docs_src/settings/app03/config.py
index e1c3ee300..942aea3e5 100644
--- a/docs_src/settings/app03/config.py
+++ b/docs_src/settings/app03/config.py
@@ -1,4 +1,4 @@
-from pydantic import BaseSettings
+from pydantic_settings import BaseSettings
class Settings(BaseSettings):
diff --git a/docs_src/settings/app03_an/config.py b/docs_src/settings/app03_an/config.py
index e1c3ee300..942aea3e5 100644
--- a/docs_src/settings/app03_an/config.py
+++ b/docs_src/settings/app03_an/config.py
@@ -1,4 +1,4 @@
-from pydantic import BaseSettings
+from pydantic_settings import BaseSettings
class Settings(BaseSettings):
diff --git a/docs_src/settings/app03_an_py39/config.py b/docs_src/settings/app03_an_py39/config.py
index e1c3ee300..942aea3e5 100644
--- a/docs_src/settings/app03_an_py39/config.py
+++ b/docs_src/settings/app03_an_py39/config.py
@@ -1,4 +1,4 @@
-from pydantic import BaseSettings
+from pydantic_settings import BaseSettings
class Settings(BaseSettings):
diff --git a/docs_src/settings/tutorial001.py b/docs_src/settings/tutorial001.py
index 0cfd1b663..d48c4c060 100644
--- a/docs_src/settings/tutorial001.py
+++ b/docs_src/settings/tutorial001.py
@@ -1,5 +1,5 @@
from fastapi import FastAPI
-from pydantic import BaseSettings
+from pydantic_settings import BaseSettings
class Settings(BaseSettings):
diff --git a/docs_src/settings/tutorial001_pv1.py b/docs_src/settings/tutorial001_pv1.py
new file mode 100644
index 000000000..0cfd1b663
--- /dev/null
+++ b/docs_src/settings/tutorial001_pv1.py
@@ -0,0 +1,21 @@
+from fastapi import FastAPI
+from pydantic import BaseSettings
+
+
+class Settings(BaseSettings):
+ app_name: str = "Awesome API"
+ admin_email: str
+ items_per_user: int = 50
+
+
+settings = Settings()
+app = FastAPI()
+
+
+@app.get("/info")
+async def info():
+ return {
+ "app_name": settings.app_name,
+ "admin_email": settings.admin_email,
+ "items_per_user": settings.items_per_user,
+ }
diff --git a/pyproject.toml b/pyproject.toml
index c421fefd9..9342367a4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -63,6 +63,7 @@ all = [
"orjson >=3.2.1",
"email_validator >=2.0.0",
"uvicorn[standard] >=0.12.0",
+ "pydantic-settings >=2.0.0",
]
[tool.hatch.version]
diff --git a/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py b/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py
index 25d6dda35..b098f259c 100644
--- a/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py
+++ b/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py
@@ -2,7 +2,7 @@ import importlib
from fastapi.testclient import TestClient
-from ...utils import needs_pydanticv1
+from ...utils import needs_pydanticv2
def get_client() -> TestClient:
@@ -14,8 +14,7 @@ def get_client() -> TestClient:
return client
-# TODO: pv2 add version with Pydantic v2
-@needs_pydanticv1
+@needs_pydanticv2
def test_disable_openapi(monkeypatch):
monkeypatch.setenv("OPENAPI_URL", "")
# Load the client after setting the env var
@@ -28,8 +27,7 @@ def test_disable_openapi(monkeypatch):
assert response.status_code == 404, response.text
-# TODO: pv2 add version with Pydantic v2
-@needs_pydanticv1
+@needs_pydanticv2
def test_root():
client = get_client()
response = client.get("/")
@@ -37,8 +35,7 @@ def test_root():
assert response.json() == {"message": "Hello World"}
-# TODO: pv2 add version with Pydantic v2
-@needs_pydanticv1
+@needs_pydanticv2
def test_default_openapi():
client = get_client()
response = client.get("/docs")
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py
index 21fc10cd8..5b0515070 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py
@@ -3,8 +3,6 @@ from dirty_equals import IsDict
from fastapi.testclient import TestClient
from fastapi.utils import match_pydantic_error_url
-# TODO: pv2 docs note to mention before it was regex instead of pattern
-
@pytest.fixture(name="client")
def get_client():
diff --git a/tests/test_tutorial/test_settings/test_app02.py b/tests/test_tutorial/test_settings/test_app02.py
index 5027ef7cf..eced88c04 100644
--- a/tests/test_tutorial/test_settings/test_app02.py
+++ b/tests/test_tutorial/test_settings/test_app02.py
@@ -1,10 +1,9 @@
from pytest import MonkeyPatch
-from ...utils import needs_pydanticv1
+from ...utils import needs_pydanticv2
-# TODO: pv2 add version with Pydantic v2
-@needs_pydanticv1
+@needs_pydanticv2
def test_settings(monkeypatch: MonkeyPatch):
from docs_src.settings.app02 import main
@@ -14,8 +13,7 @@ def test_settings(monkeypatch: MonkeyPatch):
assert settings.items_per_user == 50
-# TODO: pv2 add version with Pydantic v2
-@needs_pydanticv1
+@needs_pydanticv2
def test_override_settings():
from docs_src.settings.app02 import test_main
diff --git a/tests/test_tutorial/test_settings/test_tutorial001.py b/tests/test_tutorial/test_settings/test_tutorial001.py
new file mode 100644
index 000000000..eb30dbcee
--- /dev/null
+++ b/tests/test_tutorial/test_settings/test_tutorial001.py
@@ -0,0 +1,19 @@
+from fastapi.testclient import TestClient
+from pytest import MonkeyPatch
+
+from ...utils import needs_pydanticv2
+
+
+@needs_pydanticv2
+def test_settings(monkeypatch: MonkeyPatch):
+ monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com")
+ from docs_src.settings.tutorial001 import app
+
+ client = TestClient(app)
+ response = client.get("/info")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "app_name": "Awesome API",
+ "admin_email": "admin@example.com",
+ "items_per_user": 50,
+ }
diff --git a/tests/test_tutorial/test_settings/test_tutorial001_pv1.py b/tests/test_tutorial/test_settings/test_tutorial001_pv1.py
new file mode 100644
index 000000000..e4659de66
--- /dev/null
+++ b/tests/test_tutorial/test_settings/test_tutorial001_pv1.py
@@ -0,0 +1,19 @@
+from fastapi.testclient import TestClient
+from pytest import MonkeyPatch
+
+from ...utils import needs_pydanticv1
+
+
+@needs_pydanticv1
+def test_settings(monkeypatch: MonkeyPatch):
+ monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com")
+ from docs_src.settings.tutorial001_pv1 import app
+
+ client = TestClient(app)
+ response = client.get("/info")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "app_name": "Awesome API",
+ "admin_email": "admin@example.com",
+ "items_per_user": 50,
+ }