diff --git a/spring-boot-modules/spring-boot-api-versioning/.gitignore b/spring-boot-modules/spring-boot-api-versioning/.gitignore
new file mode 100644
index 000000000000..312265b8c1f4
--- /dev/null
+++ b/spring-boot-modules/spring-boot-api-versioning/.gitignore
@@ -0,0 +1,25 @@
+# Maven build
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+
+# IDE files
+.idea/
+*.iml
+*.ipr
+*.iws
+.vscode/
+.project
+.classpath
+.settings/
+
+# OS files
+.DS_Store
+Thumbs.db
+
+# Logs
+logs/
+*.log
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-api-versioning/README.md b/spring-boot-modules/spring-boot-api-versioning/README.md
new file mode 100644
index 000000000000..c633e58cd08a
--- /dev/null
+++ b/spring-boot-modules/spring-boot-api-versioning/README.md
@@ -0,0 +1,99 @@
+# spring-boot-api-versioning
+Demonstrating API versioning strategies in Spring Boot
+# API Versioning in Spring Boot
+
+[](https://spring.io/projects/spring-boot)
+[](https://openjdk.org/)
+[](https://maven.apache.org/)
+
+A demo project showcasing **different strategies for API versioning in Spring Boot**, including:
+
+- URI Versioning
+- Request Parameter Versioning
+- Header Versioning
+- Content Negotiation (MIME Type)
+- Native Spring Boot 4 Annotation Support
+
+---
+
+## Project Setup
+
+Clone the repository:
+
+```bash
+git clone https://github.com/your-org/api-versioning-spring-boot
+cd api-versioning-spring-boot
+```
+
+Build and run:
+
+```bash
+./mvnw spring-boot:run
+```
+
+---
+
+## Usage Examples
+
+### 1. URI Versioning
+```bash
+curl http://localhost:8080/api/v1/users
+curl http://localhost:8080/api/v2/users
+```
+
+### 2. Request Parameter Versioning
+```bash
+curl http://localhost:8080/api/users?version=1
+curl http://localhost:8080/api/users?version=2
+```
+
+### 3. Header Versioning
+```bash
+curl -H "API-VERSION: 1" http://localhost:8080/api/users
+curl -H "API-VERSION: 2" http://localhost:8080/api/users
+```
+
+### 4. Content Negotiation
+```bash
+curl -H "Accept: application/vnd.company.v1+json" http://localhost:8080/api/users
+curl -H "Accept: application/vnd.company.v2+json" http://localhost:8080/api/users
+```
+
+### 5. Native Annotation Support (Spring Boot 4)
+```bash
+curl http://localhost:8080/api/users --header "API-VERSION: 1"
+curl http://localhost:8080/api/users --header "API-VERSION: 2"
+```
+
+---
+
+## Tutorial Reference
+
+This project accompanies the post:
+**[API Versioning in Spring](#)**
+- (link will be added once published)
+---
+
+## Running Tests
+
+```bash
+./mvnw test
+```
+
+---
+
+## Best Practices
+
+- Version only when necessary
+- Document changes clearly
+- Deprecate gracefully
+- Automate testing across versions
+- Align with business needs
+
+---
+
+## 📜 License
+
+This project is licensed under the MIT License.
+
+---
diff --git a/spring-boot-modules/spring-boot-api-versioning/pom.xml b/spring-boot-modules/spring-boot-api-versioning/pom.xml
new file mode 100644
index 000000000000..1660c504e96e
--- /dev/null
+++ b/spring-boot-modules/spring-boot-api-versioning/pom.xml
@@ -0,0 +1,73 @@
+
+ 4.0.0
+
+ com.baeldung.example
+ spring-boot-api-versioning
+ 0.0.1-SNAPSHOT
+ spring-boot-api-versioning
+ API versioning strategies in Spring Boot
+
+
+ 17
+ 3.3.4
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring.boot.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ ${java.version}
+ ${java.version}
+
+ -parameters
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring.boot.version}
+
+
+
+
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/ApiVersioningDemoApplication.java b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/ApiVersioningDemoApplication.java
new file mode 100644
index 000000000000..ab63019c76b5
--- /dev/null
+++ b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/ApiVersioningDemoApplication.java
@@ -0,0 +1,11 @@
+package com.baeldung.example.apiversioning;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class ApiVersioningDemoApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(ApiVersioningDemoApplication.class, args);
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/UserParamController.java b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/UserParamController.java
new file mode 100644
index 000000000000..3fe6bd40671c
--- /dev/null
+++ b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/UserParamController.java
@@ -0,0 +1,27 @@
+package com.baeldung.example.apiversioning.controller;
+
+import com.baeldung.example.apiversioning.model.UserV2;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+public class UserParamController {
+
+@GetMapping("/api/users")
+public Object getUsers(@RequestParam(name = "version", defaultValue = "1") String version) {
+ if ("1".equals(version)) {
+ return List.of("Alice", "Bob");
+ } else if ("2".equals(version)) {
+ return List.of(
+ new UserV2("Alice", "alice@example.com", 30),
+ new UserV2("Bob", "bob@example.com", 25)
+ );
+ } else {
+ return "Unsupported API version";
+ }
+}
+
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/header/UserHeaderController.java b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/header/UserHeaderController.java
new file mode 100644
index 000000000000..07383e76ec97
--- /dev/null
+++ b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/header/UserHeaderController.java
@@ -0,0 +1,27 @@
+// src/main/java/.../controller/header/UserHeaderController.java
+package com.baeldung.example.apiversioning.controller.header;
+
+import com.baeldung.example.apiversioning.model.UserV1;
+import com.baeldung.example.apiversioning.model.UserV2;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+public class UserHeaderController {
+
+ @GetMapping(value = "/api/users", headers = "X-API-VERSION=1")
+public List getUsersV1() {
+ return List.of(new UserV1("Alice"), new UserV1("Bob"));
+}
+
+@GetMapping(value = "/api/users", headers = "X-API-VERSION=2")
+public List getUsersV2() {
+ return List.of(
+ new UserV2("Alice", "alice@example.com", 30),
+ new UserV2("Bob", "bob@example.com", 25)
+ );
+}
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/mime/UserMimeController.java b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/mime/UserMimeController.java
new file mode 100644
index 000000000000..9d2550b50b8a
--- /dev/null
+++ b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/mime/UserMimeController.java
@@ -0,0 +1,36 @@
+// src/main/java/com/baeldung/example/apiversioning/controller/mime/UserMimeController.java
+package com.baeldung.example.apiversioning.controller.mime;
+
+import com.baeldung.example.apiversioning.model.UserV1;
+import com.baeldung.example.apiversioning.model.UserV2;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+public class UserMimeController {
+
+ public static final String V1_MEDIA = "application/vnd.example.users-v1+json";
+ public static final String V2_MEDIA = "application/vnd.example.users-v2+json";
+
+ @GetMapping(value = "/api/users", produces = V1_MEDIA)
+ public List usersV1() {
+ return List.of(new UserV1("Alice"), new UserV1("Bob"));
+ }
+
+ @GetMapping(value = "/api/users", produces = V2_MEDIA)
+ public List usersV2() {
+ return List.of(
+ new UserV2("Alice", "alice@example.com", 30),
+ new UserV2("Bob", "bob@example.com", 25)
+ );
+ }
+
+ // Optional fallback
+ @GetMapping(value = "/api/users", produces = MediaType.APPLICATION_JSON_VALUE)
+ public List defaultUsers() {
+ return List.of(new UserV1("Alice"), new UserV1("Bob"));
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/negotiation/UserContentNegotiationController.java b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/negotiation/UserContentNegotiationController.java
new file mode 100644
index 000000000000..39d7752e3291
--- /dev/null
+++ b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/negotiation/UserContentNegotiationController.java
@@ -0,0 +1,20 @@
+package com.baeldung.example.apiversioning.controller.negotiation;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/users")
+public class UserContentNegotiationController {
+
+ @GetMapping(value = "/negotiation", produces = "application/vnd.col.users.v1+json")
+ public String getUsersV1() {
+ return "User list v1";
+ }
+
+ @GetMapping(value = "/negotiation", produces = "application/vnd.col.users.v2+json")
+ public String getUsersV2() {
+ return "User list v2";
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/v1/UserV1Controller.java b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/v1/UserV1Controller.java
new file mode 100644
index 000000000000..a17913d62adb
--- /dev/null
+++ b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/v1/UserV1Controller.java
@@ -0,0 +1,14 @@
+package com.baeldung.example.apiversioning.controller.v1;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/v1/users")
+public class UserV1Controller {
+ @GetMapping
+ public String getUsersV1() {
+ return "User list from API v1";
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/v2/UserV2Controller.java b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/v2/UserV2Controller.java
new file mode 100644
index 000000000000..f08158304d87
--- /dev/null
+++ b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/controller/v2/UserV2Controller.java
@@ -0,0 +1,14 @@
+package com.baeldung.example.apiversioning.controller.v2;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/v2/users")
+public class UserV2Controller {
+ @GetMapping
+ public String getUsersV2() {
+ return "User list from API v2 with extra fields";
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/model/UserV1.java b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/model/UserV1.java
new file mode 100644
index 000000000000..43fffe0a02f1
--- /dev/null
+++ b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/model/UserV1.java
@@ -0,0 +1,9 @@
+package com.baeldung.example.apiversioning.model;
+
+public class UserV1 {
+ private String name;
+ public UserV1() {}
+ public UserV1(String name) { this.name = name; }
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/model/UserV2.java b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/model/UserV2.java
new file mode 100644
index 000000000000..55aef7081ce0
--- /dev/null
+++ b/spring-boot-modules/spring-boot-api-versioning/src/main/java/com/baeldung/example/apiversioning/model/UserV2.java
@@ -0,0 +1,18 @@
+package com.baeldung.example.apiversioning.model;
+
+public class UserV2 {
+ private String name;
+ private String email;
+ private int age;
+
+ public UserV2(String name, String email, int age) {
+ this.name = name;
+ this.email = email;
+ this.age = age;
+ }
+
+ // getters
+ public String getName() { return name; }
+ public String getEmail() { return email; }
+ public int getAge() { return age; }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-api-versioning/src/test/java/com/baeldung/example/apiversioning/ApiVersioningDemoApplicationTests.java b/spring-boot-modules/spring-boot-api-versioning/src/test/java/com/baeldung/example/apiversioning/ApiVersioningDemoApplicationTests.java
new file mode 100644
index 000000000000..f8f1809ccb66
--- /dev/null
+++ b/spring-boot-modules/spring-boot-api-versioning/src/test/java/com/baeldung/example/apiversioning/ApiVersioningDemoApplicationTests.java
@@ -0,0 +1,12 @@
+package com.baeldung.example.apiversioning;
+
+import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+
+class ApiVersioningDemoApplicationTests {
+
+ @Test
+ void contextLoads() {
+ assertThat(true).isTrue();
+ }
+}