diff --git a/Web/Routes/Base.hs b/Web/Routes/Base.hs
--- a/Web/Routes/Base.hs
+++ b/Web/Routes/Base.hs
@@ -14,6 +14,7 @@
 module Web.Routes.Base
        ( encodePathInfo
        , decodePathInfo
+       , decodePathInfoParams
        ) where
 
 import Blaze.ByteString.Builder (Builder, toByteString)
@@ -22,7 +23,7 @@
 import Data.List                (intercalate, intersperse)
 import Data.Text                (Text)
 import Data.Text.Encoding       as Text (encodeUtf8, decodeUtf8)
-import Network.HTTP.Types       (encodePath, decodePathSegments, queryTextToQuery)
+import Network.HTTP.Types       (Query, encodePath, decodePath, decodePathSegments, queryTextToQuery, queryToQueryText)
 
 {-
 
@@ -281,3 +282,13 @@
 -}
 decodePathInfo :: ByteString -> [Text]
 decodePathInfo = decodePathSegments
+
+-- | Returns path segments as well as possible query string components
+--
+-- For example:
+--
+-- > decodePathInfoParams "/home?q=1"
+-- (["home"],[("q",Just "1")])
+--
+decodePathInfoParams :: ByteString -> ([Text], [(Text, Maybe Text)])
+decodePathInfoParams = fmap queryToQueryText . decodePath
diff --git a/Web/Routes/PathInfo.hs b/Web/Routes/PathInfo.hs
--- a/Web/Routes/PathInfo.hs
+++ b/Web/Routes/PathInfo.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, FlexibleInstances, TypeSynonymInstances #-}
+{-# LANGUAGE CPP, FlexibleInstances, TypeSynonymInstances, TupleSections #-}
 
 #if __GLASGOW_HASKELL__ > 702
 {-# LANGUAGE DefaultSignatures, OverloadedStrings, ScopedTypeVariables, TypeOperators #-}
@@ -18,6 +18,7 @@
     , toPathInfo
     , toPathInfoParams
     , fromPathInfo
+    , fromPathInfoParams
     , mkSitePI
     , showParseError
 #if __GLASGOW_HASKELL__ > 702
@@ -41,7 +42,7 @@
 import Text.ParserCombinators.Parsec.Error (ParseError, errorPos, errorMessages, showErrorMessages)
 import Text.ParserCombinators.Parsec.Pos   (incSourceLine, sourceName, sourceLine, sourceColumn)
 import Text.ParserCombinators.Parsec.Prim  ((<?>), GenParser, getInput, setInput, getPosition, token, parse, many)
-import Web.Routes.Base (decodePathInfo, encodePathInfo)
+import Web.Routes.Base (decodePathInfoParams, decodePathInfo, encodePathInfo)
 import Web.Routes.Site (Site(..))
 
 #if __GLASGOW_HASKELL__ > 702
@@ -286,11 +287,25 @@
 fromPathInfo :: (PathInfo url) => ByteString -> Either String url
 fromPathInfo pi =
   parseSegments fromPathSegments (decodePathInfo $ dropSlash pi)
+
+-- | parse a 'String' into '(url, Query)' using 'PathInfo'.
+--
+-- returns @Left "parse error"@ on failure
+--
+-- returns @Right (url, Query@ on success
+
+fromPathInfoParams :: (PathInfo url) => ByteString -> Either String (url, [(Text, Maybe Text)])
+fromPathInfoParams pi =
+  (,query) <$> parseSegments fromPathSegments url
   where
-    dropSlash s =
-        if ((B.singleton '/') `B.isPrefixOf` s)
-        then B.tail s
-        else s
+    (url, query) = decodePathInfoParams $ dropSlash pi
+
+-- | Removes a leading slash, if it exists
+dropSlash :: ByteString -> ByteString
+dropSlash s =
+  if ((B.singleton '/') `B.isPrefixOf` s)
+  then B.tail s
+  else s
 
 -- | turn a routing function into a 'Site' value using the 'PathInfo' class
 mkSitePI :: (PathInfo url) =>
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -2,6 +2,7 @@
 
 module Main (main) where
 
+import Data.Text (Text)
 import Test.HUnit
 import Test.QuickCheck
 import Test.Hspec
@@ -28,6 +29,11 @@
     do toPathInfo Home @?= "/home"
        toPathInfo (Article 0) @?= "/article/0"
 
+case_toPathInfoParams :: Assertion
+case_toPathInfoParams =
+    do toPathInfoParams Home [("q",Just "1"),("r",Just "2")] @?= "/home?q=1&r=2"
+       toPathInfoParams (Article 0) [("q",Just "1"),("r",Just "2")] @?= "/article/0?q=1&r=2"
+
 case_fromPathInfo :: Assertion
 case_fromPathInfo =
     do fromPathInfo "/home" @?= Right Home
@@ -36,8 +42,18 @@
          Left _ -> return ()
          url    -> assertFailure $ "expected a Left, but got: " ++ show url
 
+case_fromPathInfoParams :: Assertion
+case_fromPathInfoParams =
+    do fromPathInfoParams "/home?q=1&r=2" @?= Right (Home, [("q",Just "1"),("r",Just "2")])
+       fromPathInfoParams "/article/0?q=1&r=2" @?= Right (Article 0, [("q",Just "1"),("r",Just "2")])
+       case fromPathInfoParams "/?q=1&r=2" :: Either String (Sitemap, [(Text, Maybe Text)]) of
+         Left _ -> return ()
+         url    -> assertFailure $ "expected a Left, but got: " ++ show url
+
 main :: IO ()
 main = hspec $ do
  prop "toPathInfo" case_toPathInfo
+ prop "toPathInfoParams" case_toPathInfoParams
  prop "fromPathInfo" case_fromPathInfo
- prop "PathInfo_isomorphism"  prop_PathInfo_isomorphism
+ prop "fromPathInfoParams" case_fromPathInfoParams
+ prop "PathInfo_isomorphism" prop_PathInfo_isomorphism
diff --git a/web-routes.cabal b/web-routes.cabal
--- a/web-routes.cabal
+++ b/web-routes.cabal
@@ -1,5 +1,5 @@
 Name:             web-routes
-Version:          0.27.10
+Version:          0.27.11
 License:          BSD3
 License-File:     LICENSE
 Author:           jeremy@seereason.com
@@ -20,6 +20,7 @@
                      HUnit,
                      hspec,
                      QuickCheck,
+                     text,
                      web-routes
 
 Library
