diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # Changelog for wai-extra
 
+## 3.1.10
+
+* Added `Select` to choose between `Middleware`s [#878](https://github.com/yesodweb/wai/pull/878)
+
 ## 3.1.9
 
 * Added `HealthCheckEndpoint` `Middleware`s for health check [#877](https://github.com/yesodweb/wai/pull/877)
diff --git a/Network/Wai/Handler/CGI.hs b/Network/Wai/Handler/CGI.hs
--- a/Network/Wai/Handler/CGI.hs
+++ b/Network/Wai/Handler/CGI.hs
@@ -31,11 +31,11 @@
 import Network.Socket (addrAddress, getAddrInfo)
 import Network.Wai
 import Network.Wai.Internal
+import System.IO (Handle)
+import qualified System.IO
 #if WINDOWS
 import System.Environment (getEnvironment)
 #else
-import System.IO (Handle)
-import qualified System.IO
 import qualified System.Posix.Env.ByteString as Env
 
 getEnvironment :: IO [(String, String)]
diff --git a/Network/Wai/Middleware/Select.hs b/Network/Wai/Middleware/Select.hs
new file mode 100644
--- /dev/null
+++ b/Network/Wai/Middleware/Select.hs
@@ -0,0 +1,91 @@
+---------------------------------------------------------
+-- |
+-- Module        : Network.Wai.Middleware.Select
+-- Copyright     : Michael Snoyman
+-- License       : BSD3
+--
+-- Maintainer    : Michael Snoyman <michael@snoyman.com>
+-- Stability     : Unstable
+-- Portability   : portable
+--
+-- Dynamically choose between Middlewares
+--
+-- It's useful when you want some 'Middleware's applied selectively.
+--
+-- Example: do not log health check calls:
+--
+-- > import Network.Wai
+-- > import Network.Wai.Middleware.HealthCheckEndpoint
+-- > import Network.Wai.Middleware.RequestLogger
+-- >
+-- > app' :: Application
+-- > app' =
+-- >   selectMiddleware (selectMiddlewareExceptRawPathInfo "/_healthz" logStdout)
+-- >     $ healthCheck app
+--
+-- @since 3.1.10
+--
+---------------------------------------------------------
+module Network.Wai.Middleware.Select
+  ( -- * Middleware selection
+    MiddlewareSelection (..),
+    selectMiddleware,
+
+    -- * Helpers
+    selectMiddlewareOn,
+    selectMiddlewareOnRawPathInfo,
+    selectMiddlewareExceptRawPathInfo,
+    passthroughMiddleware,
+  )
+where
+
+import Control.Applicative ((<|>))
+import Data.ByteString (ByteString)
+import Data.Maybe (fromMaybe)
+import Network.Wai
+
+--------------------------------------------------
+-- * Middleware selection
+--------------------------------------------------
+
+-- | Relevant Middleware for a given 'Request'.
+newtype MiddlewareSelection = MiddlewareSelection
+  { applySelectedMiddleware :: Request -> Maybe Middleware
+  }
+
+instance Semigroup MiddlewareSelection where
+  MiddlewareSelection f <> MiddlewareSelection g =
+    MiddlewareSelection $ \req -> f req <|> g req
+
+instance Monoid MiddlewareSelection where
+  mempty = MiddlewareSelection $ const Nothing
+
+-- | Create the 'Middleware' dynamically applying 'MiddlewareSelection'.
+selectMiddleware :: MiddlewareSelection -> Middleware
+selectMiddleware selection app request respond =
+  mw app request respond
+  where
+    mw :: Middleware
+    mw = fromMaybe passthroughMiddleware (applySelectedMiddleware selection request)
+
+--------------------------------------------------
+-- * Helpers
+--------------------------------------------------
+
+passthroughMiddleware :: Middleware
+passthroughMiddleware = id
+
+-- | Use the 'Middleware' when the predicate holds.
+selectMiddlewareOn :: (Request -> Bool) -> Middleware -> MiddlewareSelection
+selectMiddlewareOn doesApply mw = MiddlewareSelection $ \request ->
+  if doesApply request
+    then Just mw
+    else Nothing
+
+-- | Use the `Middleware` for the given 'rawPathInfo'.
+selectMiddlewareOnRawPathInfo :: ByteString -> Middleware -> MiddlewareSelection
+selectMiddlewareOnRawPathInfo path = selectMiddlewareOn ((== path) . rawPathInfo)
+
+-- | Use the `Middleware` for all 'rawPathInfo' except then given one.
+selectMiddlewareExceptRawPathInfo :: ByteString -> Middleware -> MiddlewareSelection
+selectMiddlewareExceptRawPathInfo path = selectMiddlewareOn ((/= path) . rawPathInfo)
diff --git a/test/Network/Wai/Middleware/SelectSpec.hs b/test/Network/Wai/Middleware/SelectSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Network/Wai/Middleware/SelectSpec.hs
@@ -0,0 +1,64 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Network.Wai.Middleware.SelectSpec
+  ( main,
+    spec,
+  )
+where
+
+import Data.ByteString (ByteString)
+#if __GLASGOW_HASKELL__ < 804
+import Data.Monoid ((<>))
+#endif
+import Network.HTTP.Types (Status, status200, status401, status500)
+import Network.Wai
+import Network.Wai.Middleware.Select
+import Network.Wai.Test (SResponse (simpleStatus), request, runSession)
+import Test.Hspec
+
+main :: IO ()
+main = hspec spec
+
+spec :: Spec
+spec = describe "Select" $ do
+  it "With empty select should passthrough" $
+    runApp (selectMiddleware mempty) "/" `shouldReturn` status200
+  it "With other path select should passthrough" $
+    runApp (selectMiddleware $ selectOverride "/_" status401) "/" `shouldReturn` status200
+  it "With path select should hit override" $
+    runApp (selectMiddleware $ selectOverride "/_" status401) "/_" `shouldReturn` status401
+  it "With twice path select should hit first override" $
+    runApp (selectMiddleware $ selectOverride "/_" status401 <> selectOverride "/_" status500) "/_"
+      `shouldReturn` status401
+  it "With two paths select should hit first matching (first)" $
+    runApp (selectMiddleware $ selectOverride "/_" status401 <> selectOverride "/-" status500) "/_"
+      `shouldReturn` status401
+  it "With two paths select should hit first matching (last)" $
+    runApp (selectMiddleware $ selectOverride "/_" status401 <> selectOverride "/-" status500) "/-"
+      `shouldReturn` status500
+  it "With other two paths select should passthrough" $
+    runApp (selectMiddleware $ selectOverride "/_" status401 <> selectOverride "/-" status500) "/"
+      `shouldReturn` status200
+  it "With mempty then the path select should hit the pass" $
+    runApp (selectMiddleware $ mempty <> selectOverride "/-" status500) "/-"
+      `shouldReturn` status500
+
+runApp :: Middleware -> ByteString -> IO Status
+runApp mw path =
+  fmap simpleStatus $
+    runSession
+      (request $ defaultRequest {rawPathInfo = path})
+      $ mw app
+
+app :: Application
+app = constApp status200
+
+constApp :: Status -> Application
+constApp status _ respond = respond $ responseLBS status [] ""
+
+overrideMiddleware :: Application -> Middleware
+overrideMiddleware = const
+
+selectOverride :: ByteString -> Status -> MiddlewareSelection
+selectOverride path status = selectMiddlewareOnRawPathInfo path $ overrideMiddleware $ constApp status
diff --git a/wai-extra.cabal b/wai-extra.cabal
--- a/wai-extra.cabal
+++ b/wai-extra.cabal
@@ -1,5 +1,5 @@
 Name:                wai-extra
-Version:             3.1.9
+Version:             3.1.10
 Synopsis:            Provides some basic WAI handlers and middleware.
 description:
   Provides basic WAI handler and middleware functionality:
@@ -57,6 +57,10 @@
   .
   Rewrite request path info based on a custom conversion rules.
   .
+  * Select
+  .
+  Dynamically choose between Middlewares.
+  .
   * Stream Files
   .
   Convert ResponseFile type responses into ResponseStream type.
@@ -137,6 +141,7 @@
                      Network.Wai.Middleware.Local
                      Network.Wai.Middleware.RequestLogger
                      Network.Wai.Middleware.RequestLogger.JSON
+                     Network.Wai.Middleware.Select
                      Network.Wai.Middleware.Gzip
                      Network.Wai.Middleware.Jsonp
                      Network.Wai.Middleware.MethodOverride
@@ -192,6 +197,7 @@
                      Network.Wai.Middleware.RealIpSpec
                      Network.Wai.Middleware.RequestSizeLimitSpec
                      Network.Wai.Middleware.RoutedSpec
+                     Network.Wai.Middleware.SelectSpec
                      Network.Wai.Middleware.StripHeadersSpec
                      Network.Wai.Middleware.TimeoutSpec
                      WaiExtraSpec
