diff --git a/geo-types/src/geometry/geometry_collection.rs b/geo-types/src/geometry/geometry_collection.rs
index ce5bb2338..75c7e672c 100644
--- a/geo-types/src/geometry/geometry_collection.rs
+++ b/geo-types/src/geometry/geometry_collection.rs
@@ -1,4 +1,8 @@
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+use crate::{coord, Point, Rect};
 use crate::{CoordNum, Geometry};
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+use num_traits::Bounded;
 
 use alloc::vec;
 use alloc::vec::Vec;
@@ -247,6 +251,58 @@ impl<'a, T: CoordNum> GeometryCollection<T> {
     }
 }
 
+// Return a new rectangle that encompasses the provided rectangles
+fn bounding_rect_merge<T: CoordNum>(a: Rect<T>, b: Rect<T>) -> Rect<T> {
+    Rect::new(
+        coord! {
+            x: crate::private_utils::partial_min(a.min().x, b.min().x),
+            y: crate::private_utils::partial_min(a.min().y, b.min().y),
+        },
+        coord! {
+            x: crate::private_utils::partial_max(a.max().x, b.max().x),
+            y: crate::private_utils::partial_max(a.max().y, b.max().y),
+        },
+    )
+}
+
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+macro_rules! impl_rstar_geometry_collection {
+    ($rstar:ident) => {
+        impl<T> $rstar::RTreeObject for GeometryCollection<T>
+        where
+            T: ::num_traits::Float + ::$rstar::RTreeNum,
+        {
+            type Envelope = ::$rstar::AABB<Point<T>>;
+
+            fn envelope(&self) -> Self::Envelope {
+                let bounding_rect = self.iter().fold(None, |acc, next| {
+                    let next_bounding_rect = next.envelope();
+                    let lower = next_bounding_rect.lower();
+                    let upper = next_bounding_rect.upper();
+                    let rect = Rect::new(lower, upper);
+                    Some(bounding_rect_merge(acc.unwrap(), rect))
+                });
+                match bounding_rect {
+                    None => ::$rstar::AABB::from_corners(
+                        Point::new(Bounded::min_value(), Bounded::min_value()),
+                        Point::new(Bounded::max_value(), Bounded::max_value()),
+                    ),
+                    Some(b) => ::$rstar::AABB::from_corners(
+                        Point::new(b.min().x, b.min().y),
+                        Point::new(b.max().x, b.max().y),
+                    ),
+                }
+            }
+        }
+    };
+}
+
+#[cfg(feature = "rstar_0_8")]
+impl_rstar_geometry_collection!(rstar_0_8);
+
+#[cfg(feature = "rstar_0_9")]
+impl_rstar_geometry_collection!(rstar_0_9);
+
 #[cfg(any(feature = "approx", test))]
 impl<T> RelativeEq for GeometryCollection<T>
 where
diff --git a/geo-types/src/geometry/mod.rs b/geo-types/src/geometry/mod.rs
index 4faf01753..74262105a 100644
--- a/geo-types/src/geometry/mod.rs
+++ b/geo-types/src/geometry/mod.rs
@@ -269,6 +269,39 @@ where
     }
 }
 
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+macro_rules! impl_rstar_geometry {
+    ($rstar:ident) => {
+        impl<T> $rstar::RTreeObject for Geometry<T>
+        where
+            T: ::num_traits::Float + ::$rstar::RTreeNum,
+        {
+            type Envelope = ::$rstar::AABB<Point<T>>;
+
+            fn envelope(&self) -> Self::Envelope {
+                match self {
+                    Self::Point(x) => x.envelope(),
+                    Self::Line(x) => x.envelope(),
+                    Self::LineString(x) => x.envelope(),
+                    Self::Polygon(x) => x.envelope(),
+                    Self::Rect(x) => x.envelope(),
+                    Self::Triangle(x) => x.envelope(),
+                    Self::MultiPoint(x) => x.envelope(),
+                    Self::MultiLineString(x) => x.envelope(),
+                    Self::MultiPolygon(x) => x.envelope(),
+                    Self::GeometryCollection(x) => x.envelope(),
+                }
+            }
+        }
+    };
+}
+
+#[cfg(feature = "rstar_0_8")]
+impl_rstar_geometry!(rstar_0_8);
+
+#[cfg(feature = "rstar_0_9")]
+impl_rstar_geometry!(rstar_0_9);
+
 #[cfg(any(feature = "approx", test))]
 impl<T> RelativeEq for Geometry<T>
 where
diff --git a/geo-types/src/geometry/multi_line_string.rs b/geo-types/src/geometry/multi_line_string.rs
index 5cc84b515..ae28a9e8d 100644
--- a/geo-types/src/geometry/multi_line_string.rs
+++ b/geo-types/src/geometry/multi_line_string.rs
@@ -1,3 +1,8 @@
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+use crate::Point;
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+use num_traits::Bounded;
+
 use crate::{CoordNum, LineString};
 
 use alloc::vec;
@@ -118,6 +123,40 @@ impl<T: CoordNum> MultiLineString<T> {
     }
 }
 
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+macro_rules! impl_rstar_multi_linestring {
+    ($rstar:ident) => {
+        impl<T> $rstar::RTreeObject for MultiLineString<T>
+        where
+            T: ::num_traits::Float + ::$rstar::RTreeNum,
+        {
+            type Envelope = ::$rstar::AABB<Point<T>>;
+
+            fn envelope(&self) -> Self::Envelope {
+                let bounding_rect = crate::private_utils::get_bounding_rect(
+                    self.iter().flat_map(|line| line.0.iter().cloned()),
+                );
+                match bounding_rect {
+                    None => ::$rstar::AABB::from_corners(
+                        Point::new(Bounded::min_value(), Bounded::min_value()),
+                        Point::new(Bounded::max_value(), Bounded::max_value()),
+                    ),
+                    Some(b) => ::$rstar::AABB::from_corners(
+                        Point::new(b.min().x, b.min().y),
+                        Point::new(b.max().x, b.max().y),
+                    ),
+                }
+            }
+        }
+    };
+}
+
+#[cfg(feature = "rstar_0_8")]
+impl_rstar_multi_linestring!(rstar_0_8);
+
+#[cfg(feature = "rstar_0_9")]
+impl_rstar_multi_linestring!(rstar_0_9);
+
 #[cfg(any(feature = "approx", test))]
 impl<T> RelativeEq for MultiLineString<T>
 where
diff --git a/geo-types/src/geometry/multi_point.rs b/geo-types/src/geometry/multi_point.rs
index c59622013..2c22b9cbe 100644
--- a/geo-types/src/geometry/multi_point.rs
+++ b/geo-types/src/geometry/multi_point.rs
@@ -1,7 +1,8 @@
 use crate::{CoordNum, Point};
-
 #[cfg(any(feature = "approx", test))]
 use approx::{AbsDiffEq, RelativeEq};
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+use num_traits::Bounded;
 
 use alloc::vec;
 use alloc::vec::Vec;
@@ -99,6 +100,39 @@ impl<T: CoordNum> MultiPoint<T> {
     }
 }
 
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+macro_rules! impl_rstar_multi_point {
+    ($rstar:ident) => {
+        impl<T> $rstar::RTreeObject for MultiPoint<T>
+        where
+            T: ::num_traits::Float + ::$rstar::RTreeNum,
+        {
+            type Envelope = ::$rstar::AABB<Point<T>>;
+
+            fn envelope(&self) -> Self::Envelope {
+                let bounding_rect =
+                    crate::private_utils::get_bounding_rect(self.0.iter().map(|p| p.0));
+                match bounding_rect {
+                    None => ::$rstar::AABB::from_corners(
+                        Point::new(Bounded::min_value(), Bounded::min_value()),
+                        Point::new(Bounded::max_value(), Bounded::max_value()),
+                    ),
+                    Some(b) => ::$rstar::AABB::from_corners(
+                        Point::new(b.min().x, b.min().y),
+                        Point::new(b.max().x, b.max().y),
+                    ),
+                }
+            }
+        }
+    };
+}
+
+#[cfg(feature = "rstar_0_8")]
+impl_rstar_multi_point!(rstar_0_8);
+
+#[cfg(feature = "rstar_0_9")]
+impl_rstar_multi_point!(rstar_0_9);
+
 #[cfg(any(feature = "approx", test))]
 impl<T> RelativeEq for MultiPoint<T>
 where
diff --git a/geo-types/src/geometry/multi_polygon.rs b/geo-types/src/geometry/multi_polygon.rs
index 15116353e..dce637804 100644
--- a/geo-types/src/geometry/multi_polygon.rs
+++ b/geo-types/src/geometry/multi_polygon.rs
@@ -1,4 +1,8 @@
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+use crate::Point;
 use crate::{CoordNum, Polygon};
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+use num_traits::Bounded;
 
 use alloc::vec;
 use alloc::vec::Vec;
@@ -91,6 +95,41 @@ impl<T: CoordNum> MultiPolygon<T> {
     }
 }
 
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+macro_rules! impl_rstar_multi_polygon {
+    ($rstar:ident) => {
+        impl<T> $rstar::RTreeObject for MultiPolygon<T>
+        where
+            T: ::num_traits::Float + ::$rstar::RTreeNum,
+        {
+            type Envelope = ::$rstar::AABB<Point<T>>;
+
+            fn envelope(&self) -> Self::Envelope {
+                let bounding_rect = crate::private_utils::get_bounding_rect(
+                    self.iter()
+                        .flat_map(|poly| poly.exterior().0.iter().cloned()),
+                );
+                match bounding_rect {
+                    None => ::$rstar::AABB::from_corners(
+                        Point::new(Bounded::min_value(), Bounded::min_value()),
+                        Point::new(Bounded::max_value(), Bounded::max_value()),
+                    ),
+                    Some(b) => ::$rstar::AABB::from_corners(
+                        Point::new(b.min().x, b.min().y),
+                        Point::new(b.max().x, b.max().y),
+                    ),
+                }
+            }
+        }
+    };
+}
+
+#[cfg(feature = "rstar_0_8")]
+impl_rstar_multi_polygon!(rstar_0_8);
+
+#[cfg(feature = "rstar_0_9")]
+impl_rstar_multi_polygon!(rstar_0_9);
+
 #[cfg(any(feature = "approx", test))]
 impl<T> RelativeEq for MultiPolygon<T>
 where
diff --git a/geo-types/src/geometry/rect.rs b/geo-types/src/geometry/rect.rs
index 9d8a7b77d..76e77a55c 100644
--- a/geo-types/src/geometry/rect.rs
+++ b/geo-types/src/geometry/rect.rs
@@ -1,5 +1,7 @@
 use crate::{coord, polygon, Coord, CoordFloat, CoordNum, Line, Polygon};
 
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+use crate::Point;
 #[cfg(any(feature = "approx", test))]
 use approx::{AbsDiffEq, RelativeEq};
 
@@ -378,6 +380,31 @@ impl<T: CoordFloat> Rect<T> {
 
 static RECT_INVALID_BOUNDS_ERROR: &str = "Failed to create Rect: 'min' coordinate's x/y value must be smaller or equal to the 'max' x/y value";
 
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+macro_rules! impl_rstar_rect {
+    ($rstar:ident) => {
+        impl<T> $rstar::RTreeObject for Rect<T>
+        where
+            T: ::num_traits::Float + ::$rstar::RTreeNum,
+        {
+            type Envelope = ::$rstar::AABB<Point<T>>;
+
+            fn envelope(&self) -> Self::Envelope {
+                ::$rstar::AABB::from_corners(
+                    Point::new(self.min().x, self.min().y),
+                    Point::new(self.max().x, self.max().y),
+                )
+            }
+        }
+    };
+}
+
+#[cfg(feature = "rstar_0_8")]
+impl_rstar_rect!(rstar_0_8);
+
+#[cfg(feature = "rstar_0_9")]
+impl_rstar_rect!(rstar_0_9);
+
 #[cfg(any(feature = "approx", test))]
 impl<T> RelativeEq for Rect<T>
 where
diff --git a/geo-types/src/geometry/triangle.rs b/geo-types/src/geometry/triangle.rs
index 831e57cb1..eb5f86076 100644
--- a/geo-types/src/geometry/triangle.rs
+++ b/geo-types/src/geometry/triangle.rs
@@ -1,4 +1,11 @@
 use crate::{polygon, Coord, CoordNum, Line, Polygon};
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+use num_traits::Bounded;
+
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+use crate::private_utils::get_bounding_rect;
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+use crate::Point;
 
 #[cfg(any(feature = "approx", test))]
 use approx::{AbsDiffEq, RelativeEq};
@@ -63,6 +70,38 @@ impl<IC: Into<Coord<T>> + Copy, T: CoordNum> From<[IC; 3]> for Triangle<T> {
     }
 }
 
+#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
+macro_rules! impl_rstar_triangle {
+    ($rstar:ident) => {
+        impl<T> $rstar::RTreeObject for Triangle<T>
+        where
+            T: ::num_traits::Float + ::$rstar::RTreeNum,
+        {
+            type Envelope = ::$rstar::AABB<Point<T>>;
+
+            fn envelope(&self) -> Self::Envelope {
+                let bounding_rect = get_bounding_rect(self.to_array());
+                match bounding_rect {
+                    None => ::$rstar::AABB::from_corners(
+                        Point::new(Bounded::min_value(), Bounded::min_value()),
+                        Point::new(Bounded::max_value(), Bounded::max_value()),
+                    ),
+                    Some(b) => ::$rstar::AABB::from_corners(
+                        Point::new(b.min().x, b.min().y),
+                        Point::new(b.max().x, b.max().y),
+                    ),
+                }
+            }
+        }
+    };
+}
+
+#[cfg(feature = "rstar_0_8")]
+impl_rstar_triangle!(rstar_0_8);
+
+#[cfg(feature = "rstar_0_9")]
+impl_rstar_triangle!(rstar_0_9);
+
 #[cfg(any(feature = "approx", test))]
 impl<T> RelativeEq for Triangle<T>
 where
diff --git a/geo-types/src/private_utils.rs b/geo-types/src/private_utils.rs
index 1311a7b4f..e251e3e1d 100644
--- a/geo-types/src/private_utils.rs
+++ b/geo-types/src/private_utils.rs
@@ -5,6 +5,24 @@
 
 use crate::{Coord, CoordFloat, CoordNum, Line, LineString, Point, Rect};
 
+// The Rust standard library has `max` for `Ord`, but not for `PartialOrd`
+pub fn partial_max<T: PartialOrd>(a: T, b: T) -> T {
+    if a > b {
+        a
+    } else {
+        b
+    }
+}
+
+// The Rust standard library has `min` for `Ord`, but not for `PartialOrd`
+pub fn partial_min<T: PartialOrd>(a: T, b: T) -> T {
+    if a < b {
+        a
+    } else {
+        b
+    }
+}
+
 pub fn line_string_bounding_rect<T>(line_string: &LineString<T>) -> Option<Rect<T>>
 where
     T: CoordNum,