diff --git a/axum-core/Cargo.toml b/axum-core/Cargo.toml
index dbe5346c..2897ce38 100644
--- a/axum-core/Cargo.toml
+++ b/axum-core/Cargo.toml
@@ -12,7 +12,6 @@ repository = "https://github.com/tokio-rs/axum"
 version = "0.3.0-rc.3" # remember to also bump the version that axum depends on
 
 [dependencies]
-async-trait = "0.1"
 bytes = "1.0"
 futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
 http = "0.2.7"
diff --git a/axum-core/src/ext_traits/mod.rs b/axum-core/src/ext_traits/mod.rs
index 02595fbe..16549c02 100644
--- a/axum-core/src/ext_traits/mod.rs
+++ b/axum-core/src/ext_traits/mod.rs
@@ -6,16 +6,14 @@ mod tests {
     use std::convert::Infallible;
 
     use crate::extract::{FromRef, FromRequestParts};
-    use async_trait::async_trait;
     use http::request::Parts;
 
     #[derive(Debug, Default, Clone, Copy)]
     pub(crate) struct State<S>(pub(crate) S);
 
-    #[async_trait]
     impl<OuterState, InnerState> FromRequestParts<OuterState> for State<InnerState>
     where
-        InnerState: FromRef<OuterState>,
+        InnerState: FromRef<OuterState> + 'static,
         OuterState: Send + Sync,
     {
         type Rejection = Infallible;
@@ -32,7 +30,6 @@ mod tests {
     // some extractor that requires the state, such as `SignedCookieJar`
     pub(crate) struct RequiresState(pub(crate) String);
 
-    #[async_trait]
     impl<S> FromRequestParts<S> for RequiresState
     where
         S: Send + Sync,
diff --git a/axum-core/src/ext_traits/request.rs b/axum-core/src/ext_traits/request.rs
index 05ca77ea..aa7f4047 100644
--- a/axum-core/src/ext_traits/request.rs
+++ b/axum-core/src/ext_traits/request.rs
@@ -1,7 +1,7 @@
 use crate::extract::{DefaultBodyLimitKind, FromRequest, FromRequestParts};
-use futures_util::future::BoxFuture;
 use http::Request;
 use http_body::Limited;
+use std::future::Future;
 
 mod sealed {
     pub trait Sealed<B> {}
@@ -16,10 +16,9 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
     ///
     /// Note this consumes the request. Use [`RequestExt::extract_parts`] if you're not extracting
     /// the body and don't want to consume the request.
-    fn extract<E, M>(self) -> BoxFuture<'static, Result<E, E::Rejection>>
+    fn extract<E, M>(self) -> impl Future<Output = Result<E, E::Rejection>> + 'static
     where
-        E: FromRequest<(), B, M> + 'static,
-        M: 'static;
+        E: FromRequest<(), B, M>;
 
     /// Apply an extractor that requires some state to this `Request`.
     ///
@@ -27,17 +26,20 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
     ///
     /// Note this consumes the request. Use [`RequestExt::extract_parts_with_state`] if you're not
     /// extracting the body and don't want to consume the request.
-    fn extract_with_state<E, S, M>(self, state: &S) -> BoxFuture<'_, Result<E, E::Rejection>>
+    fn extract_with_state<E, S, M>(
+        self,
+        state: &S,
+    ) -> impl Future<Output = Result<E, E::Rejection>> + '_
     where
-        E: FromRequest<S, B, M> + 'static,
+        E: FromRequest<S, B, M>,
         S: Send + Sync;
 
     /// Apply a parts extractor to this `Request`.
     ///
     /// This is just a convenience for `E::from_request_parts(parts, state)`.
-    fn extract_parts<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>>
+    fn extract_parts<E>(&mut self) -> impl Future<Output = Result<E, E::Rejection>> + '_
     where
-        E: FromRequestParts<()> + 'static;
+        E: FromRequestParts<()>;
 
     /// Apply a parts extractor that requires some state to this `Request`.
     ///
@@ -45,9 +47,9 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
     fn extract_parts_with_state<'a, E, S>(
         &'a mut self,
         state: &'a S,
-    ) -> BoxFuture<'a, Result<E, E::Rejection>>
+    ) -> impl Future<Output = Result<E, E::Rejection>> + 'a
     where
-        E: FromRequestParts<S> + 'static,
+        E: FromRequestParts<S>,
         S: Send + Sync;
 
     /// Apply the [default body limit](crate::extract::DefaultBodyLimit).
@@ -63,27 +65,29 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
 
 impl<B> RequestExt<B> for Request<B>
 where
-    B: Send + 'static,
+    B: Send,
 {
-    fn extract<E, M>(self) -> BoxFuture<'static, Result<E, E::Rejection>>
+    fn extract<E, M>(self) -> impl Future<Output = Result<E, E::Rejection>> + 'static
     where
-        E: FromRequest<(), B, M> + 'static,
-        M: 'static,
+        E: FromRequest<(), B, M>,
     {
         self.extract_with_state(&())
     }
 
-    fn extract_with_state<E, S, M>(self, state: &S) -> BoxFuture<'_, Result<E, E::Rejection>>
+    fn extract_with_state<E, S, M>(
+        self,
+        state: &S,
+    ) -> impl Future<Output = Result<E, E::Rejection>> + '_
     where
-        E: FromRequest<S, B, M> + 'static,
+        E: FromRequest<S, B, M>,
         S: Send + Sync,
     {
         E::from_request(self, state)
     }
 
-    fn extract_parts<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>>
+    fn extract_parts<E>(&mut self) -> impl Future<Output = Result<E, E::Rejection>> + '_
     where
-        E: FromRequestParts<()> + 'static,
+        E: FromRequestParts<()>,
     {
         self.extract_parts_with_state(&())
     }
@@ -91,9 +95,9 @@ where
     fn extract_parts_with_state<'a, E, S>(
         &'a mut self,
         state: &'a S,
-    ) -> BoxFuture<'a, Result<E, E::Rejection>>
+    ) -> impl Future<Output = Result<E, E::Rejection>> + 'a
     where
-        E: FromRequestParts<S> + 'static,
+        E: FromRequestParts<S>,
         S: Send + Sync,
     {
         let mut req = Request::new(());
@@ -145,7 +149,6 @@ mod tests {
         ext_traits::tests::{RequiresState, State},
         extract::FromRef,
     };
-    use async_trait::async_trait;
     use http::Method;
     use hyper::Body;
 
@@ -209,7 +212,6 @@ mod tests {
         body: String,
     }
 
-    #[async_trait]
     impl<S, B> FromRequest<S, B> for WorksForCustomExtractor
     where
         S: Send + Sync,
diff --git a/axum-core/src/ext_traits/request_parts.rs b/axum-core/src/ext_traits/request_parts.rs
index 7e136d58..d9eb35f0 100644
--- a/axum-core/src/ext_traits/request_parts.rs
+++ b/axum-core/src/ext_traits/request_parts.rs
@@ -1,6 +1,6 @@
 use crate::extract::FromRequestParts;
-use futures_util::future::BoxFuture;
 use http::request::Parts;
+use std::future::Future;
 
 mod sealed {
     pub trait Sealed {}
@@ -12,7 +12,7 @@ pub trait RequestPartsExt: sealed::Sealed + Sized {
     /// Apply an extractor to this `Parts`.
     ///
     /// This is just a convenience for `E::from_request_parts(parts, &())`.
-    fn extract<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>>
+    fn extract<E>(&mut self) -> impl Future<Output = Result<E, E::Rejection>> + '_
     where
         E: FromRequestParts<()> + 'static;
 
@@ -22,14 +22,14 @@ pub trait RequestPartsExt: sealed::Sealed + Sized {
     fn extract_with_state<'a, E, S>(
         &'a mut self,
         state: &'a S,
-    ) -> BoxFuture<'a, Result<E, E::Rejection>>
+    ) -> impl Future<Output = Result<E, E::Rejection>> + 'a
     where
-        E: FromRequestParts<S> + 'static,
+        E: FromRequestParts<S>,
         S: Send + Sync;
 }
 
 impl RequestPartsExt for Parts {
-    fn extract<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>>
+    fn extract<E>(&mut self) -> impl Future<Output = Result<E, E::Rejection>> + '_
     where
         E: FromRequestParts<()> + 'static,
     {
@@ -39,9 +39,9 @@ impl RequestPartsExt for Parts {
     fn extract_with_state<'a, E, S>(
         &'a mut self,
         state: &'a S,
-    ) -> BoxFuture<'a, Result<E, E::Rejection>>
+    ) -> impl Future<Output = Result<E, E::Rejection>> + 'a
     where
-        E: FromRequestParts<S> + 'static,
+        E: FromRequestParts<S>,
         S: Send + Sync,
     {
         E::from_request_parts(self, state)
@@ -57,7 +57,6 @@ mod tests {
         ext_traits::tests::{RequiresState, State},
         extract::FromRef,
     };
-    use async_trait::async_trait;
     use http::{Method, Request};
 
     #[tokio::test]
@@ -90,7 +89,6 @@ mod tests {
         from_state: String,
     }
 
-    #[async_trait]
     impl<S> FromRequestParts<S> for WorksForCustomExtractor
     where
         S: Send + Sync,
diff --git a/axum-core/src/extract/mod.rs b/axum-core/src/extract/mod.rs
index 2eb37ea4..57e013e6 100644
--- a/axum-core/src/extract/mod.rs
+++ b/axum-core/src/extract/mod.rs
@@ -5,9 +5,9 @@
 //! [`axum::extract`]: https://docs.rs/axum/latest/axum/extract/index.html
 
 use crate::response::IntoResponse;
-use async_trait::async_trait;
 use http::{request::Parts, Request};
 use std::convert::Infallible;
+use std::future::Future;
 
 pub mod rejection;
 
@@ -38,20 +38,22 @@ mod private {
 /// See [`axum::extract`] for more general docs about extraxtors.
 ///
 /// [`axum::extract`]: https://docs.rs/axum/0.6.0-rc.2/axum/extract/index.html
-#[async_trait]
 #[cfg_attr(
     nightly_error_messages,
     rustc_on_unimplemented(
         note = "Function argument is not a valid axum extractor. \nSee `https://docs.rs/axum/latest/axum/extract/index.html` for details",
     )
 )]
-pub trait FromRequestParts<S>: Sized {
+pub trait FromRequestParts<S>: Sized + 'static {
     /// If the extractor fails it'll use this "rejection" type. A rejection is
     /// a kind of error that can be converted into a response.
-    type Rejection: IntoResponse;
+    type Rejection: IntoResponse + 'static;
 
     /// Perform the extraction.
-    async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection>;
+    fn from_request_parts<'a>(
+        parts: &'a mut Parts,
+        state: &'a S,
+    ) -> impl Future<Output = Result<Self, Self::Rejection>> + Send + 'a;
 }
 
 /// Types that can be created from requests.
@@ -87,7 +89,6 @@ pub trait FromRequestParts<S>: Sized {
 ///
 /// struct MyExtractor;
 ///
-/// #[async_trait]
 /// impl<S, B> FromRequest<S, B> for MyExtractor
 /// where
 ///     // these bounds are required by `async_trait`
@@ -107,38 +108,41 @@ pub trait FromRequestParts<S>: Sized {
 ///
 /// [`http::Request<B>`]: http::Request
 /// [`axum::extract`]: https://docs.rs/axum/0.6.0-rc.2/axum/extract/index.html
-#[async_trait]
 #[cfg_attr(
     nightly_error_messages,
     rustc_on_unimplemented(
         note = "Function argument is not a valid axum extractor. \nSee `https://docs.rs/axum/latest/axum/extract/index.html` for details",
     )
 )]
-pub trait FromRequest<S, B, M = private::ViaRequest>: Sized {
+pub trait FromRequest<S, B, M = private::ViaRequest>: Sized + 'static {
     /// If the extractor fails it'll use this "rejection" type. A rejection is
     /// a kind of error that can be converted into a response.
-    type Rejection: IntoResponse;
+    type Rejection: IntoResponse + 'static;
 
     /// Perform the extraction.
-    async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection>;
+    fn from_request(
+        req: Request<B>,
+        state: &S,
+    ) -> impl Future<Output = Result<Self, Self::Rejection>> + Send + '_;
 }
 
-#[async_trait]
 impl<S, B, T> FromRequest<S, B, private::ViaParts> for T
 where
-    B: Send + 'static,
+    B: Send,
     S: Send + Sync,
     T: FromRequestParts<S>,
 {
     type Rejection = <Self as FromRequestParts<S>>::Rejection;
 
-    async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
+    fn from_request(
+        req: Request<B>,
+        state: &S,
+    ) -> impl Future<Output = Result<Self, Self::Rejection>> + '_ {
         let (mut parts, _) = req.into_parts();
-        Self::from_request_parts(&mut parts, state).await
+        async move { Self::from_request_parts(&mut parts, state).await }
     }
 }
 
-#[async_trait]
 impl<S, T> FromRequestParts<S> for Option<T>
 where
     T: FromRequestParts<S>,
@@ -154,7 +158,6 @@ where
     }
 }
 
-#[async_trait]
 impl<S, T, B> FromRequest<S, B> for Option<T>
 where
     T: FromRequest<S, B>,
@@ -168,7 +171,6 @@ where
     }
 }
 
-#[async_trait]
 impl<S, T> FromRequestParts<S> for Result<T, T::Rejection>
 where
     T: FromRequestParts<S>,
@@ -181,16 +183,19 @@ where
     }
 }
 
-#[async_trait]
 impl<S, T, B> FromRequest<S, B> for Result<T, T::Rejection>
 where
     T: FromRequest<S, B>,
-    B: Send + 'static,
+    B: Send,
     S: Send + Sync,
 {
     type Rejection = Infallible;
 
-    async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
-        Ok(T::from_request(req, state).await)
+    fn from_request(
+        req: Request<B>,
+        state: &S,
+    ) -> impl Future<Output = Result<Self, Self::Rejection>> + '_ {
+        let fut = T::from_request(req, state);
+        async move { Ok(fut.await) }
     }
 }
diff --git a/axum-core/src/extract/request_parts.rs b/axum-core/src/extract/request_parts.rs
index 05d7d727..6254caae 100644
--- a/axum-core/src/extract/request_parts.rs
+++ b/axum-core/src/extract/request_parts.rs
@@ -1,14 +1,12 @@
 use super::{rejection::*, FromRequest, FromRequestParts};
 use crate::{BoxError, RequestExt};
-use async_trait::async_trait;
 use bytes::Bytes;
 use http::{request::Parts, HeaderMap, Method, Request, Uri, Version};
 use std::convert::Infallible;
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for Request<B>
 where
-    B: Send,
+    B: Send + 'static,
     S: Send + Sync,
 {
     type Rejection = Infallible;
@@ -18,7 +16,6 @@ where
     }
 }
 
-#[async_trait]
 impl<S> FromRequestParts<S> for Method
 where
     S: Send + Sync,
@@ -30,7 +27,6 @@ where
     }
 }
 
-#[async_trait]
 impl<S> FromRequestParts<S> for Uri
 where
     S: Send + Sync,
@@ -42,7 +38,6 @@ where
     }
 }
 
-#[async_trait]
 impl<S> FromRequestParts<S> for Version
 where
     S: Send + Sync,
@@ -59,7 +54,6 @@ where
 /// Prefer using [`TypedHeader`] to extract only the headers you need.
 ///
 /// [`TypedHeader`]: https://docs.rs/axum/latest/axum/extract/struct.TypedHeader.html
-#[async_trait]
 impl<S> FromRequestParts<S> for HeaderMap
 where
     S: Send + Sync,
@@ -71,7 +65,6 @@ where
     }
 }
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for Bytes
 where
     B: http_body::Body + Send + 'static,
@@ -95,7 +88,6 @@ where
     }
 }
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for String
 where
     B: http_body::Body + Send + 'static,
@@ -122,7 +114,6 @@ where
     }
 }
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for Parts
 where
     B: Send + 'static,
diff --git a/axum-core/src/extract/tuple.rs b/axum-core/src/extract/tuple.rs
index 728135b2..d48ae264 100644
--- a/axum-core/src/extract/tuple.rs
+++ b/axum-core/src/extract/tuple.rs
@@ -1,10 +1,8 @@
 use super::{FromRequest, FromRequestParts};
 use crate::response::{IntoResponse, Response};
-use async_trait::async_trait;
 use http::request::{Parts, Request};
 use std::convert::Infallible;
 
-#[async_trait]
 impl<S> FromRequestParts<S> for ()
 where
     S: Send + Sync,
@@ -20,7 +18,6 @@ macro_rules! impl_from_request {
     (
         [$($ty:ident),*], $last:ident
     ) => {
-        #[async_trait]
         #[allow(non_snake_case, unused_mut, unused_variables)]
         impl<S, $($ty,)* $last> FromRequestParts<S> for ($($ty,)* $last,)
         where
@@ -46,7 +43,6 @@ macro_rules! impl_from_request {
 
         // This impl must not be generic over M, otherwise it would conflict with the blanket
         // implementation of `FromRequest<S, B, Mut>` for `T: FromRequestParts<S>`.
-        #[async_trait]
         #[allow(non_snake_case, unused_mut, unused_variables)]
         impl<S, B, $($ty,)* $last> FromRequest<S, B> for ($($ty,)* $last,)
         where
diff --git a/axum-core/src/lib.rs b/axum-core/src/lib.rs
index 974e5e18..6aa90c03 100644
--- a/axum-core/src/lib.rs
+++ b/axum-core/src/lib.rs
@@ -9,6 +9,7 @@
 //! [`axum`]: https://crates.io/crates/axum
 //! [`axum-core`]: http://crates.io/crates/axum-core
 
+#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
 #![warn(
     clippy::all,
     clippy::dbg_macro,
@@ -45,7 +46,11 @@
     missing_docs
 )]
 #![deny(unreachable_pub, private_in_public)]
-#![allow(elided_lifetimes_in_paths, clippy::type_complexity)]
+#![allow(
+    elided_lifetimes_in_paths,
+    incomplete_features,
+    clippy::type_complexity
+)]
 #![forbid(unsafe_code)]
 #![cfg_attr(test, allow(clippy::float_cmp))]
 
diff --git a/axum-extra/src/either.rs b/axum-extra/src/either.rs
index 2e3af8b8..7c19947c 100755
--- a/axum-extra/src/either.rs
+++ b/axum-extra/src/either.rs
@@ -15,8 +15,7 @@
 //! // extractors for checking permissions
 //! struct AdminPermissions {}
 //!
-//! #[async_trait]
-//! impl<S> FromRequestParts<S> for AdminPermissions
+//! //! impl<S> FromRequestParts<S> for AdminPermissions
 //! where
 //!     S: Send + Sync,
 //! {
@@ -29,8 +28,7 @@
 //!
 //! struct User {}
 //!
-//! #[async_trait]
-//! impl<S> FromRequestParts<S> for User
+//! //! impl<S> FromRequestParts<S> for User
 //! where
 //!     S: Send + Sync,
 //! {
@@ -94,7 +92,6 @@
 //! [`IntoResponse::into_response`]: https://docs.rs/axum/0.5/axum/response/index.html#returning-different-response-types
 
 use axum::{
-    async_trait,
     extract::FromRequestParts,
     response::{IntoResponse, Response},
 };
@@ -225,7 +222,6 @@ macro_rules! impl_traits_for_either {
         [$($ident:ident),* $(,)?],
         $last:ident $(,)?
     ) => {
-        #[async_trait]
         impl<S, $($ident),*, $last> FromRequestParts<S> for $either<$($ident),*, $last>
         where
             $($ident: FromRequestParts<S>),*,
@@ -236,12 +232,14 @@ macro_rules! impl_traits_for_either {
 
             async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
                 $(
-                    if let Ok(value) = FromRequestParts::from_request_parts(parts, state).await {
+                    if let Ok(value) =
+                        <$ident as FromRequestParts<_>>::from_request_parts(parts, state).await
+                    {
                         return Ok(Self::$ident(value));
                     }
                 )*
 
-                FromRequestParts::from_request_parts(parts, state).await.map(Self::$last)
+                <$last as FromRequestParts<_>>::from_request_parts(parts, state).await.map(Self::$last)
             }
         }
 
diff --git a/axum-extra/src/extract/cached.rs b/axum-extra/src/extract/cached.rs
index 03565c77..1ba02324 100644
--- a/axum-extra/src/extract/cached.rs
+++ b/axum-extra/src/extract/cached.rs
@@ -1,7 +1,4 @@
-use axum::{
-    async_trait,
-    extract::{Extension, FromRequestParts},
-};
+use axum::extract::{Extension, FromRequestParts};
 use http::request::Parts;
 use std::ops::{Deref, DerefMut};
 
@@ -30,7 +27,6 @@ use std::ops::{Deref, DerefMut};
 /// #[derive(Clone)]
 /// struct Session { /* ... */ }
 ///
-/// #[async_trait]
 /// impl<S> FromRequestParts<S> for Session
 /// where
 ///     S: Send + Sync,
@@ -45,7 +41,6 @@ use std::ops::{Deref, DerefMut};
 ///
 /// struct CurrentUser { /* ... */ }
 ///
-/// #[async_trait]
 /// impl<S> FromRequestParts<S> for CurrentUser
 /// where
 ///     S: Send + Sync,
@@ -88,7 +83,6 @@ pub struct Cached<T>(pub T);
 #[derive(Clone)]
 struct CachedEntry<T>(T);
 
-#[async_trait]
 impl<S, T> FromRequestParts<S> for Cached<T>
 where
     S: Send + Sync,
@@ -140,7 +134,6 @@ mod tests {
         #[derive(Clone, Debug, PartialEq, Eq)]
         struct Extractor(Instant);
 
-        #[async_trait]
         impl<S> FromRequestParts<S> for Extractor
         where
             S: Send + Sync,
diff --git a/axum-extra/src/extract/cookie/mod.rs b/axum-extra/src/extract/cookie/mod.rs
index 0c6bcc4c..d866e1fc 100644
--- a/axum-extra/src/extract/cookie/mod.rs
+++ b/axum-extra/src/extract/cookie/mod.rs
@@ -3,7 +3,6 @@
 //! See [`CookieJar`], [`SignedCookieJar`], and [`PrivateCookieJar`] for more details.
 
 use axum::{
-    async_trait,
     extract::FromRequestParts,
     response::{IntoResponse, IntoResponseParts, Response, ResponseParts},
 };
@@ -88,7 +87,6 @@ pub struct CookieJar {
     jar: cookie::CookieJar,
 }
 
-#[async_trait]
 impl<S> FromRequestParts<S> for CookieJar
 where
     S: Send + Sync,
diff --git a/axum-extra/src/extract/cookie/private.rs b/axum-extra/src/extract/cookie/private.rs
index cceea95e..48a514b9 100644
--- a/axum-extra/src/extract/cookie/private.rs
+++ b/axum-extra/src/extract/cookie/private.rs
@@ -1,6 +1,5 @@
 use super::{cookies_from_request, set_cookies, Cookie, Key};
 use axum::{
-    async_trait,
     extract::{FromRef, FromRequestParts},
     response::{IntoResponse, IntoResponseParts, Response, ResponseParts},
 };
@@ -87,11 +86,10 @@ impl<K> fmt::Debug for PrivateCookieJar<K> {
     }
 }
 
-#[async_trait]
 impl<S, K> FromRequestParts<S> for PrivateCookieJar<K>
 where
     S: Send + Sync,
-    K: FromRef<S> + Into<Key>,
+    K: FromRef<S> + Into<Key> + 'static,
 {
     type Rejection = Infallible;
 
diff --git a/axum-extra/src/extract/cookie/signed.rs b/axum-extra/src/extract/cookie/signed.rs
index 1ef837a2..4d215f82 100644
--- a/axum-extra/src/extract/cookie/signed.rs
+++ b/axum-extra/src/extract/cookie/signed.rs
@@ -1,6 +1,5 @@
 use super::{cookies_from_request, set_cookies};
 use axum::{
-    async_trait,
     extract::{FromRef, FromRequestParts},
     response::{IntoResponse, IntoResponseParts, Response, ResponseParts},
 };
@@ -105,11 +104,10 @@ impl<K> fmt::Debug for SignedCookieJar<K> {
     }
 }
 
-#[async_trait]
 impl<S, K> FromRequestParts<S> for SignedCookieJar<K>
 where
     S: Send + Sync,
-    K: FromRef<S> + Into<Key>,
+    K: FromRef<S> + Into<Key> + 'static,
 {
     type Rejection = Infallible;
 
diff --git a/axum-extra/src/extract/form.rs b/axum-extra/src/extract/form.rs
index df33e5ca..c6422311 100644
--- a/axum-extra/src/extract/form.rs
+++ b/axum-extra/src/extract/form.rs
@@ -1,5 +1,4 @@
 use axum::{
-    async_trait,
     body::HttpBody,
     extract::{rejection::RawFormRejection, FromRequest, RawForm},
     response::{IntoResponse, Response},
@@ -51,10 +50,9 @@ impl<T> Deref for Form<T> {
     }
 }
 
-#[async_trait]
 impl<T, S, B> FromRequest<S, B> for Form<T>
 where
-    T: DeserializeOwned,
+    T: DeserializeOwned + 'static,
     B: HttpBody + Send + 'static,
     B::Data: Send,
     B::Error: Into<BoxError>,
diff --git a/axum-extra/src/extract/query.rs b/axum-extra/src/extract/query.rs
index 8c829dd5..99c77c43 100644
--- a/axum-extra/src/extract/query.rs
+++ b/axum-extra/src/extract/query.rs
@@ -1,5 +1,4 @@
 use axum::{
-    async_trait,
     extract::FromRequestParts,
     response::{IntoResponse, Response},
     Error,
@@ -57,10 +56,9 @@ use std::{fmt, ops::Deref};
 #[derive(Debug, Clone, Copy, Default)]
 pub struct Query<T>(pub T);
 
-#[async_trait]
 impl<T, S> FromRequestParts<S> for Query<T>
 where
-    T: DeserializeOwned,
+    T: DeserializeOwned + 'static,
     S: Send + Sync,
 {
     type Rejection = QueryRejection;
diff --git a/axum-extra/src/extract/with_rejection.rs b/axum-extra/src/extract/with_rejection.rs
index f3a0f04e..eafa0a06 100644
--- a/axum-extra/src/extract/with_rejection.rs
+++ b/axum-extra/src/extract/with_rejection.rs
@@ -1,4 +1,3 @@
-use axum::async_trait;
 use axum::extract::{FromRequest, FromRequestParts};
 use axum::response::IntoResponse;
 use http::request::Parts;
@@ -108,13 +107,12 @@ impl<E, R> DerefMut for WithRejection<E, R> {
     }
 }
 
-#[async_trait]
 impl<B, E, R, S> FromRequest<S, B> for WithRejection<E, R>
 where
     B: Send + 'static,
     S: Send + Sync,
-    E: FromRequest<S, B>,
-    R: From<E::Rejection> + IntoResponse,
+    E: FromRequest<S, B> + 'static,
+    R: From<E::Rejection> + IntoResponse + 'static,
 {
     type Rejection = R;
 
@@ -124,12 +122,11 @@ where
     }
 }
 
-#[async_trait]
 impl<E, R, S> FromRequestParts<S> for WithRejection<E, R>
 where
     S: Send + Sync,
     E: FromRequestParts<S>,
-    R: From<E::Rejection> + IntoResponse,
+    R: From<E::Rejection> + IntoResponse + 'static,
 {
     type Rejection = R;
 
@@ -153,7 +150,6 @@ mod tests {
         struct TestExtractor;
         struct TestRejection;
 
-        #[async_trait]
         impl<S> FromRequestParts<S> for TestExtractor
         where
             S: Send + Sync,
diff --git a/axum-extra/src/handler/mod.rs b/axum-extra/src/handler/mod.rs
index 305c9c8c..33680bc4 100644
--- a/axum-extra/src/handler/mod.rs
+++ b/axum-extra/src/handler/mod.rs
@@ -66,8 +66,7 @@ pub trait HandlerCallWithExtractors<T, S, B>: Sized {
     /// // extractors for checking permissions
     /// struct AdminPermissions {}
     ///
-    /// #[async_trait]
-    /// impl<S> FromRequestParts<S> for AdminPermissions
+    ///     /// impl<S> FromRequestParts<S> for AdminPermissions
     /// where
     ///     S: Send + Sync,
     /// {
@@ -80,8 +79,7 @@ pub trait HandlerCallWithExtractors<T, S, B>: Sized {
     ///
     /// struct User {}
     ///
-    /// #[async_trait]
-    /// impl<S> FromRequestParts<S> for User
+    ///     /// impl<S> FromRequestParts<S> for User
     /// where
     ///     S: Send + Sync,
     /// {
diff --git a/axum-extra/src/json_lines.rs b/axum-extra/src/json_lines.rs
index 83336311..f4028eaf 100644
--- a/axum-extra/src/json_lines.rs
+++ b/axum-extra/src/json_lines.rs
@@ -1,7 +1,6 @@
 //! Newline delimited JSON extractor and response.
 
 use axum::{
-    async_trait,
     body::{HttpBody, StreamBody},
     extract::FromRequest,
     response::{IntoResponse, Response},
@@ -99,13 +98,12 @@ impl<S> JsonLines<S, AsResponse> {
     }
 }
 
-#[async_trait]
 impl<S, B, T> FromRequest<S, B> for JsonLines<T, AsExtractor>
 where
     B: HttpBody + Send + 'static,
     B::Data: Into<Bytes>,
     B::Error: Into<BoxError>,
-    T: DeserializeOwned,
+    T: DeserializeOwned + 'static,
     S: Send + Sync,
 {
     type Rejection = Infallible;
diff --git a/axum-extra/src/lib.rs b/axum-extra/src/lib.rs
index f7c23682..56cf1c3b 100644
--- a/axum-extra/src/lib.rs
+++ b/axum-extra/src/lib.rs
@@ -23,6 +23,7 @@
 //!
 //! [`axum`]: https://crates.io/crates/axum
 
+#![feature(async_fn_in_trait)]
 #![warn(
     clippy::all,
     clippy::dbg_macro,
@@ -59,7 +60,11 @@
     missing_docs
 )]
 #![deny(unreachable_pub, private_in_public)]
-#![allow(elided_lifetimes_in_paths, clippy::type_complexity)]
+#![allow(
+    elided_lifetimes_in_paths,
+    incomplete_features,
+    clippy::type_complexity
+)]
 #![forbid(unsafe_code)]
 #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
 #![cfg_attr(test, allow(clippy::float_cmp))]
diff --git a/axum-extra/src/protobuf.rs b/axum-extra/src/protobuf.rs
index ddb70122..860a4682 100644
--- a/axum-extra/src/protobuf.rs
+++ b/axum-extra/src/protobuf.rs
@@ -1,7 +1,6 @@
 //! Protocol Buffer extractor and response.
 
 use axum::{
-    async_trait,
     body::{Bytes, HttpBody},
     extract::{rejection::BytesRejection, FromRequest},
     response::{IntoResponse, Response},
@@ -96,10 +95,9 @@ use std::ops::{Deref, DerefMut};
 #[cfg_attr(docsrs, doc(cfg(feature = "protobuf")))]
 pub struct ProtoBuf<T>(pub T);
 
-#[async_trait]
 impl<T, S, B> FromRequest<S, B> for ProtoBuf<T>
 where
-    T: Message + Default,
+    T: Message + Default + 'static,
     B: HttpBody + Send + 'static,
     B::Data: Send,
     B::Error: Into<BoxError>,
diff --git a/axum-macros/src/from_request.rs b/axum-macros/src/from_request.rs
index 7f6e76c9..15f92f1f 100644
--- a/axum-macros/src/from_request.rs
+++ b/axum-macros/src/from_request.rs
@@ -384,7 +384,6 @@ fn impl_struct_by_extracting_each_field(
 
     Ok(match tr {
         Trait::FromRequest => quote! {
-            #[::axum::async_trait]
             #[automatically_derived]
             impl<#impl_generics> ::axum::extract::FromRequest<#trait_generics> for #ident
             where
@@ -404,7 +403,6 @@ fn impl_struct_by_extracting_each_field(
             }
         },
         Trait::FromRequestParts => quote! {
-            #[::axum::async_trait]
             #[automatically_derived]
             impl<#impl_generics> ::axum::extract::FromRequestParts<#trait_generics> for #ident
             where
@@ -477,7 +475,8 @@ fn extract_fields(
             let FromRequestFieldAttrs { via } = parse_attrs("from_request", &field.attrs)?;
 
             let member = member(field, index);
-            let ty_span = field.ty.span();
+            let ty = &field.ty;
+            let ty_span = ty.span();
             let into_inner = into_inner(via, ty_span);
 
             if peel_option(&field.ty).is_some() {
@@ -487,7 +486,7 @@ fn extract_fields(
                             #member: {
                                 let (mut parts, body) = req.into_parts();
                                 let value =
-                                    ::axum::extract::FromRequestParts::from_request_parts(
+                                    <$ty as ::axum::extract::FromRequestParts<_>>::from_request_parts(
                                         &mut parts,
                                         state,
                                     )
@@ -502,7 +501,7 @@ fn extract_fields(
                     Trait::FromRequestParts => {
                         quote_spanned! {ty_span=>
                             #member: {
-                                ::axum::extract::FromRequestParts::from_request_parts(
+                                <$ty as ::axum::extract::FromRequestParts<_>>::from_request_parts(
                                     parts,
                                     state,
                                 )
@@ -521,7 +520,7 @@ fn extract_fields(
                             #member: {
                                 let (mut parts, body) = req.into_parts();
                                 let value =
-                                    ::axum::extract::FromRequestParts::from_request_parts(
+                                    <$ty as ::axum::extract::FromRequestParts<_>>::from_request_parts(
                                         &mut parts,
                                         state,
                                     )
@@ -535,7 +534,7 @@ fn extract_fields(
                     Trait::FromRequestParts => {
                         quote_spanned! {ty_span=>
                             #member: {
-                                ::axum::extract::FromRequestParts::from_request_parts(
+                                <$ty as ::axum::extract::FromRequestParts<_>>::from_request_parts(
                                     parts,
                                     state,
                                 )
@@ -559,7 +558,7 @@ fn extract_fields(
                             #member: {
                                 let (mut parts, body) = req.into_parts();
                                 let value =
-                                    ::axum::extract::FromRequestParts::from_request_parts(
+                                    <$ty as ::axum::extract::FromRequestParts<_>>::from_request_parts(
                                         &mut parts,
                                         state,
                                     )
@@ -574,7 +573,7 @@ fn extract_fields(
                     Trait::FromRequestParts => {
                         quote_spanned! {ty_span=>
                             #member: {
-                                ::axum::extract::FromRequestParts::from_request_parts(
+                                <$ty as ::axum::extract::FromRequestParts<_>>::from_request_parts(
                                     parts,
                                     state,
                                 )
@@ -595,13 +594,14 @@ fn extract_fields(
         let FromRequestFieldAttrs { via } = parse_attrs("from_request", &field.attrs)?;
 
         let member = member(field, fields.len() - 1);
-        let ty_span = field.ty.span();
+        let ty = &field.ty;
+        let ty_span = ty.span();
         let into_inner = into_inner(via, ty_span);
 
         let item = if peel_option(&field.ty).is_some() {
             quote_spanned! {ty_span=>
                 #member: {
-                    ::axum::extract::FromRequest::from_request(req, state)
+                    <$ty as ::axum::extract::FromRequest<_, _>>::from_request(req, state)
                         .await
                         .ok()
                         .map(#into_inner)
@@ -610,7 +610,7 @@ fn extract_fields(
         } else if peel_result_ok(&field.ty).is_some() {
             quote_spanned! {ty_span=>
                 #member: {
-                    ::axum::extract::FromRequest::from_request(req, state)
+                    <$ty as ::axum::extract::FromRequest<_, _>>::from_request(req, state)
                         .await
                         .map(#into_inner)
                 },
@@ -624,7 +624,7 @@ fn extract_fields(
 
             quote_spanned! {ty_span=>
                 #member: {
-                    ::axum::extract::FromRequest::from_request(req, state)
+                    <$ty as ::axum::extract::FromRequest<_, _>>::from_request(req, state)
                         .await
                         .map(#into_inner)
                         .map_err(#map_err)?
@@ -822,11 +822,10 @@ fn impl_struct_by_extracting_all_at_once(
     let tokens = match tr {
         Trait::FromRequest => {
             quote_spanned! {path_span=>
-                #[::axum::async_trait]
                 #[automatically_derived]
                 impl<#impl_generics> ::axum::extract::FromRequest<#trait_generics> for #ident #ident_generics
                 where
-                    #via_path<#via_type_generics>: ::axum::extract::FromRequest<#trait_generics>,
+                    #via_path<#via_type_generics>: ::axum::extract::FromRequest<#trait_generics> + 'static,
                     #rejection_bound
                     B: ::std::marker::Send + 'static,
                     #state_bounds
@@ -837,7 +836,7 @@ fn impl_struct_by_extracting_all_at_once(
                         req: ::axum::http::Request<B>,
                         state: &#state,
                     ) -> ::std::result::Result<Self, Self::Rejection> {
-                        ::axum::extract::FromRequest::from_request(req, state)
+                        <#via_path<#via_type_generics> as ::axum::extract::FromRequest<_, _>>::from_request(req, state)
                             .await
                             .map(|#via_path(value)| #value_to_self)
                             .map_err(#map_err)
@@ -847,11 +846,10 @@ fn impl_struct_by_extracting_all_at_once(
         }
         Trait::FromRequestParts => {
             quote_spanned! {path_span=>
-                #[::axum::async_trait]
                 #[automatically_derived]
                 impl<#impl_generics> ::axum::extract::FromRequestParts<#trait_generics> for #ident #ident_generics
                 where
-                    #via_path<#via_type_generics>: ::axum::extract::FromRequestParts<#trait_generics>,
+                    #via_path<#via_type_generics>: ::axum::extract::FromRequestParts<#trait_generics> + 'static,
                     #rejection_bound
                     #state_bounds
                 {
@@ -861,7 +859,7 @@ fn impl_struct_by_extracting_all_at_once(
                         parts: &mut ::axum::http::request::Parts,
                         state: &#state,
                     ) -> ::std::result::Result<Self, Self::Rejection> {
-                        ::axum::extract::FromRequestParts::from_request_parts(parts, state)
+                        <#via_path<#via_type_generics> as ::axum::extract::FromRequestParts<_>>::from_request_parts(parts, state)
                             .await
                             .map(|#via_path(value)| #value_to_self)
                             .map_err(#map_err)
@@ -938,7 +936,6 @@ fn impl_enum_by_extracting_all_at_once(
     let tokens = match tr {
         Trait::FromRequest => {
             quote_spanned! {path_span=>
-                #[::axum::async_trait]
                 #[automatically_derived]
                 impl<#impl_generics> ::axum::extract::FromRequest<#trait_generics> for #ident
                 where
@@ -953,7 +950,7 @@ fn impl_enum_by_extracting_all_at_once(
                         req: ::axum::http::Request<B>,
                         state: &#state,
                     ) -> ::std::result::Result<Self, Self::Rejection> {
-                        ::axum::extract::FromRequest::from_request(req, state)
+                        <#path as ::axum::extract::FromRequest<_, _>>::from_request(req, state)
                             .await
                             .map(|#path(inner)| inner)
                             .map_err(#map_err)
@@ -963,7 +960,6 @@ fn impl_enum_by_extracting_all_at_once(
         }
         Trait::FromRequestParts => {
             quote_spanned! {path_span=>
-                #[::axum::async_trait]
                 #[automatically_derived]
                 impl<#impl_generics> ::axum::extract::FromRequestParts<#trait_generics> for #ident
                 where
@@ -975,7 +971,7 @@ fn impl_enum_by_extracting_all_at_once(
                         parts: &mut ::axum::http::request::Parts,
                         state: &#state,
                     ) -> ::std::result::Result<Self, Self::Rejection> {
-                        ::axum::extract::FromRequestParts::from_request_parts(parts, state)
+                        <#path as ::axum::extract::FromRequestParts<_>>::from_request_parts(parts, state)
                             .await
                             .map(|#path(inner)| inner)
                             .map_err(#map_err)
diff --git a/axum-macros/src/lib.rs b/axum-macros/src/lib.rs
index 43741ddf..680e19ee 100644
--- a/axum-macros/src/lib.rs
+++ b/axum-macros/src/lib.rs
@@ -191,7 +191,6 @@ use from_request::Trait::{FromRequest, FromRequestParts};
 ///     http::StatusCode,
 ///     headers::ContentType,
 ///     body::Bytes,
-///     async_trait,
 /// };
 ///
 /// #[derive(FromRequest)]
diff --git a/axum-macros/src/typed_path.rs b/axum-macros/src/typed_path.rs
index 6a50886f..e9f33870 100644
--- a/axum-macros/src/typed_path.rs
+++ b/axum-macros/src/typed_path.rs
@@ -133,7 +133,6 @@ fn expand_named_fields(
     let map_err_rejection = map_err_rejection(&rejection);
 
     let from_request_impl = quote! {
-        #[::axum::async_trait]
         #[automatically_derived]
         impl<S> ::axum::extract::FromRequestParts<S> for #ident
         where
@@ -238,7 +237,6 @@ fn expand_unnamed_fields(
     let map_err_rejection = map_err_rejection(&rejection);
 
     let from_request_impl = quote! {
-        #[::axum::async_trait]
         #[automatically_derived]
         impl<S> ::axum::extract::FromRequestParts<S> for #ident
         where
@@ -322,7 +320,6 @@ fn expand_unit_fields(
     };
 
     let from_request_impl = quote! {
-        #[::axum::async_trait]
         #[automatically_derived]
         impl<S> ::axum::extract::FromRequestParts<S> for #ident
         where
diff --git a/axum-macros/tests/debug_handler/fail/extract_self_mut.rs b/axum-macros/tests/debug_handler/fail/extract_self_mut.rs
index d20426e2..3f5b44d8 100644
--- a/axum-macros/tests/debug_handler/fail/extract_self_mut.rs
+++ b/axum-macros/tests/debug_handler/fail/extract_self_mut.rs
@@ -1,13 +1,8 @@
-use axum::{
-    async_trait,
-    extract::FromRequest,
-    http::Request,
-};
+use axum::{extract::FromRequest, http::Request};
 use axum_macros::debug_handler;
 
 struct A;
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for A
 where
     B: Send + 'static,
diff --git a/axum-macros/tests/debug_handler/fail/extract_self_ref.rs b/axum-macros/tests/debug_handler/fail/extract_self_ref.rs
index 77940e29..c6f57aa5 100644
--- a/axum-macros/tests/debug_handler/fail/extract_self_ref.rs
+++ b/axum-macros/tests/debug_handler/fail/extract_self_ref.rs
@@ -1,13 +1,8 @@
-use axum::{
-    async_trait,
-    extract::FromRequest,
-    http::Request,
-};
+use axum::{extract::FromRequest, http::Request};
 use axum_macros::debug_handler;
 
 struct A;
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for A
 where
     B: Send + 'static,
diff --git a/axum-macros/tests/debug_handler/pass/result_impl_into_response.rs b/axum-macros/tests/debug_handler/pass/result_impl_into_response.rs
index 782fc930..f23c9b62 100644
--- a/axum-macros/tests/debug_handler/pass/result_impl_into_response.rs
+++ b/axum-macros/tests/debug_handler/pass/result_impl_into_response.rs
@@ -1,4 +1,4 @@
-use axum::{async_trait, extract::FromRequestParts, http::request::Parts, response::IntoResponse};
+use axum::{extract::FromRequestParts, http::request::Parts, response::IntoResponse};
 use axum_macros::debug_handler;
 
 fn main() {}
@@ -115,7 +115,6 @@ impl A {
     }
 }
 
-#[async_trait]
 impl<S> FromRequestParts<S> for A
 where
     S: Send + Sync,
diff --git a/axum-macros/tests/debug_handler/pass/self_receiver.rs b/axum-macros/tests/debug_handler/pass/self_receiver.rs
index e7bf81ce..2c1a052b 100644
--- a/axum-macros/tests/debug_handler/pass/self_receiver.rs
+++ b/axum-macros/tests/debug_handler/pass/self_receiver.rs
@@ -1,13 +1,8 @@
-use axum::{
-    async_trait,
-    extract::FromRequest,
-    http::Request,
-};
+use axum::{extract::FromRequest, http::Request};
 use axum_macros::debug_handler;
 
 struct A;
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for A
 where
     B: Send + 'static,
@@ -20,7 +15,6 @@ where
     }
 }
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for Box<A>
 where
     B: Send + 'static,
diff --git a/axum-macros/tests/debug_handler/pass/set_state.rs b/axum-macros/tests/debug_handler/pass/set_state.rs
index 5c84dbd2..c710bd9b 100644
--- a/axum-macros/tests/debug_handler/pass/set_state.rs
+++ b/axum-macros/tests/debug_handler/pass/set_state.rs
@@ -1,7 +1,6 @@
-use axum_macros::debug_handler;
 use axum::extract::{FromRef, FromRequest};
-use axum::async_trait;
 use axum::http::Request;
+use axum_macros::debug_handler;
 
 #[debug_handler(state = AppState)]
 async fn handler(_: A) {}
@@ -11,7 +10,6 @@ struct AppState;
 
 struct A;
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for A
 where
     B: Send + 'static,
diff --git a/axum-macros/tests/from_request/pass/override_rejection.rs b/axum-macros/tests/from_request/pass/override_rejection.rs
index 0147c9a8..066e004f 100644
--- a/axum-macros/tests/from_request/pass/override_rejection.rs
+++ b/axum-macros/tests/from_request/pass/override_rejection.rs
@@ -1,7 +1,6 @@
 use axum::{
-    async_trait,
     extract::{rejection::ExtensionRejection, FromRequest},
-    http::{StatusCode, Request},
+    http::{Request, StatusCode},
     response::{IntoResponse, Response},
     routing::get,
     Extension, Router,
@@ -26,7 +25,6 @@ struct MyExtractor {
 
 struct OtherExtractor;
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for OtherExtractor
 where
     B: Send + 'static,
diff --git a/axum-macros/tests/from_request/pass/override_rejection_parts.rs b/axum-macros/tests/from_request/pass/override_rejection_parts.rs
index 8ef9cb22..7cc27de2 100644
--- a/axum-macros/tests/from_request/pass/override_rejection_parts.rs
+++ b/axum-macros/tests/from_request/pass/override_rejection_parts.rs
@@ -1,5 +1,4 @@
 use axum::{
-    async_trait,
     extract::{rejection::ExtensionRejection, FromRequestParts},
     http::{request::Parts, StatusCode},
     response::{IntoResponse, Response},
@@ -26,7 +25,6 @@ struct MyExtractor {
 
 struct OtherExtractor;
 
-#[async_trait]
 impl<S> FromRequestParts<S> for OtherExtractor
 where
     S: Send + Sync,
diff --git a/axum/Cargo.toml b/axum/Cargo.toml
index 06d73f04..a4879153 100644
--- a/axum/Cargo.toml
+++ b/axum/Cargo.toml
@@ -30,7 +30,6 @@ ws = ["tokio", "dep:tokio-tungstenite", "dep:sha-1", "dep:base64"]
 __private_docs = ["tower/full", "tower-http/full"]
 
 [dependencies]
-async-trait = "0.1.43"
 axum-core = { path = "../axum-core", version = "=0.3.0-rc.3" }
 bitflags = "1.0"
 bytes = "1.0"
diff --git a/axum/src/docs/extract.md b/axum/src/docs/extract.md
index e002a8b7..e7862ca2 100644
--- a/axum/src/docs/extract.md
+++ b/axum/src/docs/extract.md
@@ -423,7 +423,6 @@ use axum::{
 
 struct ExtractUserAgent(HeaderValue);
 
-#[async_trait]
 impl<S> FromRequestParts<S> for ExtractUserAgent
 where
     S: Send + Sync,
@@ -470,7 +469,6 @@ use axum::{
 
 struct ValidatedBody(Bytes);
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for ValidatedBody
 where
     Bytes: FromRequest<S, B>,
@@ -520,7 +518,6 @@ use std::convert::Infallible;
 struct MyExtractor;
 
 // `MyExtractor` implements both `FromRequest`
-#[async_trait]
 impl<S, B> FromRequest<S, B> for MyExtractor
 where
     S: Send + Sync,
@@ -535,7 +532,6 @@ where
 }
 
 // and `FromRequestParts`
-#[async_trait]
 impl<S> FromRequestParts<S> for MyExtractor
 where
     S: Send + Sync,
@@ -587,7 +583,6 @@ struct AuthenticatedUser {
     // ...
 }
 
-#[async_trait]
 impl<S> FromRequestParts<S> for AuthenticatedUser
 where
     S: Send + Sync,
@@ -777,7 +772,6 @@ struct Timing<E> {
 }
 
 // we must implement both `FromRequestParts`
-#[async_trait]
 impl<S, T> FromRequestParts<S> for Timing<T>
 where
     S: Send + Sync,
@@ -797,7 +791,6 @@ where
 }
 
 // and `FromRequest`
-#[async_trait]
 impl<S, B, T> FromRequest<S, B> for Timing<T>
 where
     B: Send + 'static,
diff --git a/axum/src/extension.rs b/axum/src/extension.rs
index 575d62ca..4396c2ca 100644
--- a/axum/src/extension.rs
+++ b/axum/src/extension.rs
@@ -1,5 +1,4 @@
 use crate::{extract::rejection::*, response::IntoResponseParts};
-use async_trait::async_trait;
 use axum_core::{
     extract::FromRequestParts,
     response::{IntoResponse, Response, ResponseParts},
@@ -72,7 +71,6 @@ use tower_service::Service;
 #[derive(Debug, Clone, Copy, Default)]
 pub struct Extension<T>(pub T);
 
-#[async_trait]
 impl<T, S> FromRequestParts<S> for Extension<T>
 where
     T: Clone + Send + Sync + 'static,
diff --git a/axum/src/extract/connect_info.rs b/axum/src/extract/connect_info.rs
index fff2b46f..ae33588e 100644
--- a/axum/src/extract/connect_info.rs
+++ b/axum/src/extract/connect_info.rs
@@ -6,7 +6,6 @@
 
 use super::{Extension, FromRequestParts};
 use crate::middleware::AddExtension;
-use async_trait::async_trait;
 use http::request::Parts;
 use hyper::server::conn::AddrStream;
 use std::{
@@ -128,7 +127,6 @@ opaque_future! {
 #[derive(Clone, Copy, Debug)]
 pub struct ConnectInfo<T>(pub T);
 
-#[async_trait]
 impl<S, T> FromRequestParts<S> for ConnectInfo<T>
 where
     S: Send + Sync,
diff --git a/axum/src/extract/host.rs b/axum/src/extract/host.rs
index f92a6227..9cf0c638 100644
--- a/axum/src/extract/host.rs
+++ b/axum/src/extract/host.rs
@@ -2,7 +2,6 @@ use super::{
     rejection::{FailedToResolveHost, HostRejection},
     FromRequestParts,
 };
-use async_trait::async_trait;
 use http::{
     header::{HeaderMap, FORWARDED},
     request::Parts,
@@ -23,7 +22,6 @@ const X_FORWARDED_HOST_HEADER_KEY: &str = "X-Forwarded-Host";
 #[derive(Debug, Clone)]
 pub struct Host(pub String);
 
-#[async_trait]
 impl<S> FromRequestParts<S> for Host
 where
     S: Send + Sync,
diff --git a/axum/src/extract/matched_path.rs b/axum/src/extract/matched_path.rs
index 064a9726..a70a6a3a 100644
--- a/axum/src/extract/matched_path.rs
+++ b/axum/src/extract/matched_path.rs
@@ -1,6 +1,5 @@
 use super::{rejection::*, FromRequestParts};
 use crate::routing::{RouteId, NEST_TAIL_PARAM_CAPTURE};
-use async_trait::async_trait;
 use http::request::Parts;
 use std::{collections::HashMap, sync::Arc};
 
@@ -104,7 +103,6 @@ impl MatchedPath {
     }
 }
 
-#[async_trait]
 impl<S> FromRequestParts<S> for MatchedPath
 where
     S: Send + Sync,
diff --git a/axum/src/extract/multipart.rs b/axum/src/extract/multipart.rs
index 76dd52de..493b4674 100644
--- a/axum/src/extract/multipart.rs
+++ b/axum/src/extract/multipart.rs
@@ -5,7 +5,6 @@
 use super::{BodyStream, FromRequest};
 use crate::body::{Bytes, HttpBody};
 use crate::BoxError;
-use async_trait::async_trait;
 use axum_core::RequestExt;
 use futures_util::stream::Stream;
 use http::header::{HeaderMap, CONTENT_TYPE};
@@ -54,7 +53,6 @@ pub struct Multipart {
     inner: multer::Multipart<'static>,
 }
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for Multipart
 where
     B: HttpBody + Send + 'static,
diff --git a/axum/src/extract/path/mod.rs b/axum/src/extract/path/mod.rs
index ad4e5eb4..78123591 100644
--- a/axum/src/extract/path/mod.rs
+++ b/axum/src/extract/path/mod.rs
@@ -7,7 +7,6 @@ use crate::{
     extract::{rejection::*, FromRequestParts},
     routing::url_params::UrlParams,
 };
-use async_trait::async_trait;
 use axum_core::response::{IntoResponse, Response};
 use http::{request::Parts, StatusCode};
 use serde::de::DeserializeOwned;
@@ -166,10 +165,9 @@ impl<T> DerefMut for Path<T> {
     }
 }
 
-#[async_trait]
 impl<T, S> FromRequestParts<S> for Path<T>
 where
-    T: DeserializeOwned + Send,
+    T: DeserializeOwned + Send + 'static,
     S: Send + Sync,
 {
     type Rejection = PathRejection;
diff --git a/axum/src/extract/query.rs b/axum/src/extract/query.rs
index 23cb02dc..39d14acf 100644
--- a/axum/src/extract/query.rs
+++ b/axum/src/extract/query.rs
@@ -1,5 +1,4 @@
 use super::{rejection::*, FromRequestParts};
-use async_trait::async_trait;
 use http::request::Parts;
 use serde::de::DeserializeOwned;
 use std::ops::Deref;
@@ -49,10 +48,9 @@ use std::ops::Deref;
 #[derive(Debug, Clone, Copy, Default)]
 pub struct Query<T>(pub T);
 
-#[async_trait]
 impl<T, S> FromRequestParts<S> for Query<T>
 where
-    T: DeserializeOwned,
+    T: DeserializeOwned + 'static,
     S: Send + Sync,
 {
     type Rejection = QueryRejection;
@@ -85,7 +83,7 @@ mod tests {
 
     async fn check<T>(uri: impl AsRef<str>, value: T)
     where
-        T: DeserializeOwned + PartialEq + Debug,
+        T: DeserializeOwned + PartialEq + Debug + 'static,
     {
         let req = Request::builder().uri(uri.as_ref()).body(()).unwrap();
         assert_eq!(Query::<T>::from_request(req, &()).await.unwrap().0, value);
diff --git a/axum/src/extract/raw_form.rs b/axum/src/extract/raw_form.rs
index 3f9f67f6..c4fa7b40 100644
--- a/axum/src/extract/raw_form.rs
+++ b/axum/src/extract/raw_form.rs
@@ -1,4 +1,3 @@
-use async_trait::async_trait;
 use axum_core::extract::FromRequest;
 use bytes::{Bytes, BytesMut};
 use http::{Method, Request};
@@ -34,7 +33,6 @@ use crate::{body::HttpBody, BoxError};
 #[derive(Debug)]
 pub struct RawForm(pub Bytes);
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for RawForm
 where
     B: HttpBody + Send + 'static,
diff --git a/axum/src/extract/raw_query.rs b/axum/src/extract/raw_query.rs
index 0e507cfc..744f87ed 100644
--- a/axum/src/extract/raw_query.rs
+++ b/axum/src/extract/raw_query.rs
@@ -1,5 +1,4 @@
 use super::FromRequestParts;
-use async_trait::async_trait;
 use http::request::Parts;
 use std::convert::Infallible;
 
@@ -27,7 +26,6 @@ use std::convert::Infallible;
 #[derive(Debug)]
 pub struct RawQuery(pub Option<String>);
 
-#[async_trait]
 impl<S> FromRequestParts<S> for RawQuery
 where
     S: Send + Sync,
diff --git a/axum/src/extract/request_parts.rs b/axum/src/extract/request_parts.rs
index 933e7a71..6e459dac 100644
--- a/axum/src/extract/request_parts.rs
+++ b/axum/src/extract/request_parts.rs
@@ -3,7 +3,6 @@ use crate::{
     body::{Body, Bytes, HttpBody},
     BoxError, Error,
 };
-use async_trait::async_trait;
 use futures_util::stream::Stream;
 use http::{request::Parts, Request, Uri};
 use std::{
@@ -85,7 +84,6 @@ use sync_wrapper::SyncWrapper;
 pub struct OriginalUri(pub Uri);
 
 #[cfg(feature = "original-uri")]
-#[async_trait]
 impl<S> FromRequestParts<S> for OriginalUri
 where
     S: Send + Sync,
@@ -145,7 +143,6 @@ impl Stream for BodyStream {
     }
 }
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for BodyStream
 where
     B: HttpBody + Send + 'static,
@@ -208,10 +205,9 @@ fn body_stream_traits() {
 #[derive(Debug, Default, Clone)]
 pub struct RawBody<B = Body>(pub B);
 
-#[async_trait]
 impl<S, B> FromRequest<S, B> for RawBody<B>
 where
-    B: Send,
+    B: Send + 'static,
     S: Send + Sync,
 {
     type Rejection = Infallible;
diff --git a/axum/src/extract/state.rs b/axum/src/extract/state.rs
index 966d72a0..35291ed2 100644
--- a/axum/src/extract/state.rs
+++ b/axum/src/extract/state.rs
@@ -1,4 +1,3 @@
-use async_trait::async_trait;
 use axum_core::extract::{FromRef, FromRequestParts};
 use http::request::Parts;
 use std::{
@@ -8,7 +7,7 @@ use std::{
 
 /// Extractor for state.
 ///
-/// See ["Accessing state in middleware"][state-from-middleware] for how to  
+/// See ["Accessing state in middleware"][state-from-middleware] for how to
 /// access state in middleware.
 ///
 /// [state-from-middleware]: crate::middleware#accessing-state-in-middleware
@@ -151,13 +150,11 @@ use std::{
 /// ```rust
 /// use axum_core::extract::{FromRequestParts, FromRef};
 /// use http::request::Parts;
-/// use async_trait::async_trait;
 /// use std::convert::Infallible;
 ///
 /// // the extractor your library provides
 /// struct MyLibraryExtractor;
 ///
-/// #[async_trait]
 /// impl<S> FromRequestParts<S> for MyLibraryExtractor
 /// where
 ///     // keep `S` generic but require that it can produce a `MyLibraryState`
@@ -231,10 +228,9 @@ use std::{
 #[derive(Debug, Default, Clone, Copy)]
 pub struct State<S>(pub S);
 
-#[async_trait]
 impl<OuterState, InnerState> FromRequestParts<OuterState> for State<InnerState>
 where
-    InnerState: FromRef<OuterState>,
+    InnerState: FromRef<OuterState> + 'static,
     OuterState: Send + Sync,
 {
     type Rejection = Infallible;
diff --git a/axum/src/extract/ws.rs b/axum/src/extract/ws.rs
index 2f55a6ba..8284a052 100644
--- a/axum/src/extract/ws.rs
+++ b/axum/src/extract/ws.rs
@@ -101,7 +101,6 @@ use crate::{
     response::Response,
     Error,
 };
-use async_trait::async_trait;
 use futures_util::{
     sink::{Sink, SinkExt},
     stream::{Stream, StreamExt},
@@ -368,7 +367,6 @@ impl OnFailedUpdgrade for DefaultOnFailedUpdgrade {
     fn call(self, _error: Error) {}
 }
 
-#[async_trait]
 impl<S> FromRequestParts<S> for WebSocketUpgrade<DefaultOnFailedUpdgrade>
 where
     S: Send + Sync,
diff --git a/axum/src/form.rs b/axum/src/form.rs
index c30b2260..43e13833 100644
--- a/axum/src/form.rs
+++ b/axum/src/form.rs
@@ -1,7 +1,6 @@
 use crate::body::HttpBody;
 use crate::extract::{rejection::*, FromRequest, RawForm};
 use crate::BoxError;
-use async_trait::async_trait;
 use axum_core::response::{IntoResponse, Response};
 use axum_core::RequestExt;
 use http::header::CONTENT_TYPE;
@@ -61,10 +60,9 @@ use std::ops::Deref;
 #[derive(Debug, Clone, Copy, Default)]
 pub struct Form<T>(pub T);
 
-#[async_trait]
 impl<T, S, B> FromRequest<S, B> for Form<T>
 where
-    T: DeserializeOwned,
+    T: DeserializeOwned + 'static,
     B: HttpBody + Send + 'static,
     B::Data: Send,
     B::Error: Into<BoxError>,
@@ -126,7 +124,10 @@ mod tests {
         page: Option<u64>,
     }
 
-    async fn check_query<T: DeserializeOwned + PartialEq + Debug>(uri: impl AsRef<str>, value: T) {
+    async fn check_query<T: DeserializeOwned + PartialEq + Debug + 'static>(
+        uri: impl AsRef<str>,
+        value: T,
+    ) {
         let req = Request::builder()
             .uri(uri.as_ref())
             .body(Empty::<Bytes>::new())
@@ -134,7 +135,7 @@ mod tests {
         assert_eq!(Form::<T>::from_request(req, &()).await.unwrap().0, value);
     }
 
-    async fn check_body<T: Serialize + DeserializeOwned + PartialEq + Debug>(value: T) {
+    async fn check_body<T: Serialize + DeserializeOwned + PartialEq + Debug + 'static>(value: T) {
         let req = Request::builder()
             .uri("http://example.com/test")
             .method(Method::POST)
diff --git a/axum/src/json.rs b/axum/src/json.rs
index ca52e069..568d451b 100644
--- a/axum/src/json.rs
+++ b/axum/src/json.rs
@@ -3,7 +3,6 @@ use crate::{
     extract::{rejection::*, FromRequest},
     BoxError,
 };
-use async_trait::async_trait;
 use axum_core::response::{IntoResponse, Response};
 use bytes::{BufMut, BytesMut};
 use http::{
@@ -99,10 +98,9 @@ use std::ops::{Deref, DerefMut};
 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
 pub struct Json<T>(pub T);
 
-#[async_trait]
 impl<T, S, B> FromRequest<S, B> for Json<T>
 where
-    T: DeserializeOwned,
+    T: DeserializeOwned + 'static,
     B: HttpBody + Send + 'static,
     B::Data: Send,
     B::Error: Into<BoxError>,
diff --git a/axum/src/lib.rs b/axum/src/lib.rs
index 60221147..3f372aca 100644
--- a/axum/src/lib.rs
+++ b/axum/src/lib.rs
@@ -391,6 +391,7 @@
 //! [`axum-core`]: http://crates.io/crates/axum-core
 //! [`State`]: crate::extract::State
 
+#![feature(async_fn_in_trait)]
 #![cfg_attr(nightly_error_messages, feature(rustc_attrs))]
 #![warn(
     clippy::all,
@@ -428,7 +429,11 @@
     missing_docs
 )]
 #![deny(unreachable_pub, private_in_public)]
-#![allow(elided_lifetimes_in_paths, clippy::type_complexity)]
+#![allow(
+    elided_lifetimes_in_paths,
+    incomplete_features,
+    clippy::type_complexity
+)]
 #![forbid(unsafe_code)]
 #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))]
 #![cfg_attr(test, allow(clippy::float_cmp))]
@@ -458,8 +463,6 @@ pub mod routing;
 #[cfg(test)]
 mod test_helpers;
 
-#[doc(no_inline)]
-pub use async_trait::async_trait;
 #[cfg(feature = "headers")]
 #[doc(no_inline)]
 pub use headers;
diff --git a/axum/src/middleware/from_extractor.rs b/axum/src/middleware/from_extractor.rs
index a6822af8..f4a75eaa 100644
--- a/axum/src/middleware/from_extractor.rs
+++ b/axum/src/middleware/from_extractor.rs
@@ -39,12 +39,10 @@ use tower_service::Service;
 ///     Router,
 ///     http::{header, StatusCode, request::Parts},
 /// };
-/// use async_trait::async_trait;
 ///
 /// // An extractor that performs authorization.
 /// struct RequireAuth;
 ///
-/// #[async_trait]
 /// impl<S> FromRequestParts<S> for RequireAuth
 /// where
 ///     S: Send + Sync,
@@ -200,7 +198,7 @@ where
 
 impl<T, E, B, S> Service<Request<B>> for FromExtractor<T, E, S>
 where
-    E: FromRequestParts<S> + 'static,
+    E: FromRequestParts<S>,
     B: Send + 'static,
     T: Service<Request<B>> + Clone,
     T::Response: IntoResponse,
@@ -304,7 +302,7 @@ where
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::{async_trait, handler::Handler, routing::get, test_helpers::*, Router};
+    use crate::{handler::Handler, routing::get, test_helpers::*, Router};
     use axum_core::extract::FromRef;
     use http::{header, request::Parts, StatusCode};
     use tower_http::limit::RequestBodyLimitLayer;
@@ -316,7 +314,6 @@ mod tests {
 
         struct RequireAuth;
 
-        #[async_trait::async_trait]
         impl<S> FromRequestParts<S> for RequireAuth
         where
             S: Send + Sync,
@@ -369,7 +366,6 @@ mod tests {
     fn works_with_request_body_limit() {
         struct MyExtractor;
 
-        #[async_trait]
         impl<S> FromRequestParts<S> for MyExtractor
         where
             S: Send + Sync,
diff --git a/axum/src/typed_header.rs b/axum/src/typed_header.rs
index 87805a82..c4ffdf1e 100644
--- a/axum/src/typed_header.rs
+++ b/axum/src/typed_header.rs
@@ -1,5 +1,4 @@
 use crate::extract::FromRequestParts;
-use async_trait::async_trait;
 use axum_core::response::{IntoResponse, IntoResponseParts, Response, ResponseParts};
 use headers::HeaderMapExt;
 use http::request::Parts;
@@ -52,10 +51,9 @@ use std::{convert::Infallible, ops::Deref};
 #[derive(Debug, Clone, Copy)]
 pub struct TypedHeader<T>(pub T);
 
-#[async_trait]
 impl<T, S> FromRequestParts<S> for TypedHeader<T>
 where
-    T: headers::Header,
+    T: headers::Header + 'static,
     S: Send + Sync,
 {
     type Rejection = TypedHeaderRejection;
diff --git a/examples/consume-body-in-extractor-or-middleware/src/main.rs b/examples/consume-body-in-extractor-or-middleware/src/main.rs
index b3363d99..cc8ba2e6 100644
--- a/examples/consume-body-in-extractor-or-middleware/src/main.rs
+++ b/examples/consume-body-in-extractor-or-middleware/src/main.rs
@@ -4,8 +4,10 @@
 //! cd examples && cargo run -p example-consume-body-in-extractor-or-middleware
 //! ```
 
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
 use axum::{
-    async_trait,
     body::{self, BoxBody, Bytes, Full},
     extract::FromRequest,
     http::{Request, StatusCode},
@@ -80,7 +82,6 @@ async fn handler(BufferRequestBody(body): BufferRequestBody) {
 struct BufferRequestBody(Bytes);
 
 // we must implement `FromRequest` (and not `FromRequestParts`) to consume the body
-#[async_trait]
 impl<S> FromRequest<S, BoxBody> for BufferRequestBody
 where
     S: Send + Sync,
diff --git a/examples/customize-extractor-error/src/custom_extractor.rs b/examples/customize-extractor-error/src/custom_extractor.rs
index d9093bc4..7aa37c93 100644
--- a/examples/customize-extractor-error/src/custom_extractor.rs
+++ b/examples/customize-extractor-error/src/custom_extractor.rs
@@ -5,7 +5,6 @@
 //! - Boilerplate: Requires creating a new extractor for every custom rejection
 //! - Complexity: Manually implementing `FromRequest` results on more complex code
 use axum::{
-    async_trait,
     extract::{rejection::JsonRejection, FromRequest, MatchedPath},
     http::Request,
     http::StatusCode,
@@ -21,10 +20,9 @@ pub async fn handler(Json(value): Json<Value>) -> impl IntoResponse {
 // We define our own `Json` extractor that customizes the error from `axum::Json`
 pub struct Json<T>(pub T);
 
-#[async_trait]
 impl<S, B, T> FromRequest<S, B> for Json<T>
 where
-    axum::Json<T>: FromRequest<S, B, Rejection = JsonRejection>,
+    axum::Json<T>: FromRequest<S, B, Rejection = JsonRejection> + 'static,
     S: Send + Sync,
     B: Send + 'static,
 {
diff --git a/examples/customize-extractor-error/src/derive_from_request.rs b/examples/customize-extractor-error/src/derive_from_request.rs
index 762d602e..14c7ed2f 100644
--- a/examples/customize-extractor-error/src/derive_from_request.rs
+++ b/examples/customize-extractor-error/src/derive_from_request.rs
@@ -11,6 +11,7 @@
 //!
 //! [`thiserror`]: https://crates.io/crates/thiserror
 //! [FromRequest#known-limitations]: https://docs.rs/axum-macros/*/axum_macros/derive.FromRequest.html#known-limitations
+
 use axum::{extract::rejection::JsonRejection, http::StatusCode, response::IntoResponse};
 use axum_macros::FromRequest;
 use serde_json::{json, Value};
diff --git a/examples/customize-extractor-error/src/main.rs b/examples/customize-extractor-error/src/main.rs
index b7b24f76..56e6866e 100644
--- a/examples/customize-extractor-error/src/main.rs
+++ b/examples/customize-extractor-error/src/main.rs
@@ -4,6 +4,9 @@
 //! cd examples && cargo run -p example-customize-extractor-error
 //! ```
 
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
 mod custom_extractor;
 mod derive_from_request;
 mod with_rejection;
diff --git a/examples/customize-path-rejection/src/main.rs b/examples/customize-path-rejection/src/main.rs
index 68baf8f8..d74fe9a1 100644
--- a/examples/customize-path-rejection/src/main.rs
+++ b/examples/customize-path-rejection/src/main.rs
@@ -4,8 +4,10 @@
 //! cd examples && cargo run -p example-customize-path-rejection
 //! ```
 
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
 use axum::{
-    async_trait,
     extract::{path::ErrorKind, rejection::PathRejection, FromRequestParts},
     http::{request::Parts, StatusCode},
     response::IntoResponse,
@@ -51,11 +53,10 @@ struct Params {
 // We define our own `Path` extractor that customizes the error from `axum::extract::Path`
 struct Path<T>(T);
 
-#[async_trait]
 impl<S, T> FromRequestParts<S> for Path<T>
 where
     // these trait bounds are copied from `impl FromRequest for axum::extract::path::Path`
-    T: DeserializeOwned + Send,
+    T: DeserializeOwned + Send + 'static,
     S: Send + Sync,
 {
     type Rejection = (StatusCode, axum::Json<PathError>);
diff --git a/examples/error-handling-and-dependency-injection/Cargo.toml b/examples/error-handling-and-dependency-injection/Cargo.toml
index 583ab15a..f275eb17 100644
--- a/examples/error-handling-and-dependency-injection/Cargo.toml
+++ b/examples/error-handling-and-dependency-injection/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
 publish = false
 
 [dependencies]
+async-trait = "0.1.58"
 axum = { path = "../../axum" }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
diff --git a/examples/error-handling-and-dependency-injection/src/main.rs b/examples/error-handling-and-dependency-injection/src/main.rs
index af897e3a..9678befc 100644
--- a/examples/error-handling-and-dependency-injection/src/main.rs
+++ b/examples/error-handling-and-dependency-injection/src/main.rs
@@ -7,8 +7,8 @@
 //! cd examples && cargo run -p example-error-handling-and-dependency-injection
 //! ```
 
+use async_trait::async_trait;
 use axum::{
-    async_trait,
     extract::{Path, State},
     http::StatusCode,
     response::{IntoResponse, Response},
diff --git a/examples/jwt/src/main.rs b/examples/jwt/src/main.rs
index 82633d96..07e041cb 100644
--- a/examples/jwt/src/main.rs
+++ b/examples/jwt/src/main.rs
@@ -6,8 +6,10 @@
 //! JWT_SECRET=secret cargo run -p example-jwt
 //! ```
 
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
 use axum::{
-    async_trait,
     extract::{FromRequestParts, TypedHeader},
     headers::{authorization::Bearer, Authorization},
     http::{request::Parts, StatusCode},
@@ -121,7 +123,6 @@ impl AuthBody {
     }
 }
 
-#[async_trait]
 impl<S> FromRequestParts<S> for Claims
 where
     S: Send + Sync,
diff --git a/examples/key-value-store/src/main.rs b/examples/key-value-store/src/main.rs
index 334e0e25..5d6c2bf7 100644
--- a/examples/key-value-store/src/main.rs
+++ b/examples/key-value-store/src/main.rs
@@ -26,7 +26,7 @@ use std::{
 use tower::{BoxError, ServiceBuilder};
 use tower_http::{
     auth::RequireAuthorizationLayer, compression::CompressionLayer, limit::RequestBodyLimitLayer,
-    trace::TraceLayer, ServiceBuilderExt,
+    trace::TraceLayer,
 };
 use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
 
diff --git a/examples/oauth/src/main.rs b/examples/oauth/src/main.rs
index ea692df8..36245c6e 100644
--- a/examples/oauth/src/main.rs
+++ b/examples/oauth/src/main.rs
@@ -8,9 +8,11 @@
 //! CLIENT_ID=REPLACE_ME CLIENT_SECRET=REPLACE_ME cargo run -p example-oauth
 //! ```
 
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
 use async_session::{MemoryStore, Session, SessionStore};
 use axum::{
-    async_trait,
     extract::{
         rejection::TypedHeaderRejectionReason, FromRef, FromRequestParts, Query, State, TypedHeader,
     },
@@ -223,7 +225,6 @@ impl IntoResponse for AuthRedirect {
     }
 }
 
-#[async_trait]
 impl<S> FromRequestParts<S> for User
 where
     MemoryStore: FromRef<S>,
diff --git a/examples/parse-body-based-on-content-type/src/main.rs b/examples/parse-body-based-on-content-type/src/main.rs
index 9167d1e0..d179e22c 100644
--- a/examples/parse-body-based-on-content-type/src/main.rs
+++ b/examples/parse-body-based-on-content-type/src/main.rs
@@ -6,8 +6,10 @@
 //! cd examples && cargo run -p example-parse-body-based-on-content-type
 //! ```
 
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
 use axum::{
-    async_trait,
     extract::FromRequest,
     http::{header::CONTENT_TYPE, Request, StatusCode},
     response::{IntoResponse, Response},
@@ -56,7 +58,6 @@ enum JsonOrForm<T, K = T> {
     Form(K),
 }
 
-#[async_trait]
 impl<S, B, T, U> FromRequest<S, B> for JsonOrForm<T, U>
 where
     B: Send + 'static,
diff --git a/examples/sessions/src/main.rs b/examples/sessions/src/main.rs
index 716ee41a..1d4d2641 100644
--- a/examples/sessions/src/main.rs
+++ b/examples/sessions/src/main.rs
@@ -4,9 +4,11 @@
 //! cd examples && cargo run -p example-sessions
 //! ```
 
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
 use async_session::{MemoryStore, Session, SessionStore as _};
 use axum::{
-    async_trait,
     extract::{FromRef, FromRequestParts, TypedHeader},
     headers::Cookie,
     http::{
@@ -80,7 +82,6 @@ enum UserIdFromSession {
     CreatedFreshUserId(FreshUserId),
 }
 
-#[async_trait]
 impl<S> FromRequestParts<S> for UserIdFromSession
 where
     MemoryStore: FromRef<S>,
diff --git a/examples/sqlx-postgres/src/main.rs b/examples/sqlx-postgres/src/main.rs
index 0330edab..ef85d2c7 100644
--- a/examples/sqlx-postgres/src/main.rs
+++ b/examples/sqlx-postgres/src/main.rs
@@ -13,8 +13,10 @@
 //! curl -X POST 127.0.0.1:3000
 //! ```
 
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
 use axum::{
-    async_trait,
     extract::{FromRef, FromRequestParts, State},
     http::{request::Parts, StatusCode},
     routing::get,
@@ -76,7 +78,6 @@ async fn using_connection_pool_extractor(
 // which setup is appropriate depends on your application
 struct DatabaseConnection(sqlx::pool::PoolConnection<sqlx::Postgres>);
 
-#[async_trait]
 impl<S> FromRequestParts<S> for DatabaseConnection
 where
     PgPool: FromRef<S>,
diff --git a/examples/tokio-postgres/src/main.rs b/examples/tokio-postgres/src/main.rs
index faef52b5..f23b49ad 100644
--- a/examples/tokio-postgres/src/main.rs
+++ b/examples/tokio-postgres/src/main.rs
@@ -4,8 +4,10 @@
 //! cd examples && cargo run -p example-tokio-postgres
 //! ```
 
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
 use axum::{
-    async_trait,
     extract::{FromRef, FromRequestParts, State},
     http::{request::Parts, StatusCode},
     routing::get,
@@ -69,7 +71,6 @@ async fn using_connection_pool_extractor(
 // which setup is appropriate depends on your application
 struct DatabaseConnection(PooledConnection<'static, PostgresConnectionManager<NoTls>>);
 
-#[async_trait]
 impl<S> FromRequestParts<S> for DatabaseConnection
 where
     ConnectionPool: FromRef<S>,
diff --git a/examples/validator/Cargo.toml b/examples/validator/Cargo.toml
index 8c35019f..816a22d3 100644
--- a/examples/validator/Cargo.toml
+++ b/examples/validator/Cargo.toml
@@ -5,7 +5,6 @@ publish = false
 version = "0.1.0"
 
 [dependencies]
-async-trait = "0.1"
 axum = { path = "../../axum" }
 http-body = "0.4.3"
 serde = { version = "1.0", features = ["derive"] }
diff --git a/examples/validator/src/main.rs b/examples/validator/src/main.rs
index 359be614..808f2084 100644
--- a/examples/validator/src/main.rs
+++ b/examples/validator/src/main.rs
@@ -10,7 +10,9 @@
 //! -> <h1>Hello, LT!</h1>
 //! ```
 
-use async_trait::async_trait;
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
 use axum::{
     extract::{rejection::FormRejection, Form, FromRequest},
     http::{Request, StatusCode},
@@ -59,10 +61,9 @@ async fn handler(ValidatedForm(input): ValidatedForm<NameInput>) -> Html<String>
 #[derive(Debug, Clone, Copy, Default)]
 pub struct ValidatedForm<T>(pub T);
 
-#[async_trait]
 impl<T, S, B> FromRequest<S, B> for ValidatedForm<T>
 where
-    T: DeserializeOwned + Validate,
+    T: DeserializeOwned + Validate + 'static,
     S: Send + Sync,
     Form<T>: FromRequest<S, B, Rejection = FormRejection>,
     B: Send + 'static,
diff --git a/examples/versioning/src/main.rs b/examples/versioning/src/main.rs
index 6948eb1d..f1e141a6 100644
--- a/examples/versioning/src/main.rs
+++ b/examples/versioning/src/main.rs
@@ -4,8 +4,10 @@
 //! cd examples && cargo run -p example-versioning
 //! ```
 
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
 use axum::{
-    async_trait,
     extract::{FromRequestParts, Path},
     http::{request::Parts, StatusCode},
     response::{IntoResponse, Response},
@@ -47,7 +49,6 @@ enum Version {
     V3,
 }
 
-#[async_trait]
 impl<S> FromRequestParts<S> for Version
 where
     S: Send + Sync,