diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,13 @@
+* 0.2.0.0 Daniel Patterson <dbp@dbpmail.net> 2015-11-5
+
+  - Add `heistServe`, which serves templates according to path.
+  - Remove `heistLens` and `setHeist` from `HeistContext` type class,
+    as they aren't used.
+
 * 0.1.1.0 Daniel Patterson <dbp@dbpmail.net> 2015-10-30
 
-  Add `tag'`, which builds splices without atttributes.
+  - Add `tag'`, which builds splices without atttributes.
 
 * 0.1.0.0 Daniel Patterson <dbp@dbpmail.net> 2015-10-26
 
-  Initial release.
+  - Initial release.
diff --git a/fn-extra.cabal b/fn-extra.cabal
--- a/fn-extra.cabal
+++ b/fn-extra.cabal
@@ -1,5 +1,5 @@
 name:                fn-extra
-version:             0.1.1.0
+version:             0.2.0.0
 synopsis:            Extras for Fn, a functional web framework.
 description:         Please see README.
 homepage:            http://github.com/dbp/fn#readme
@@ -29,6 +29,7 @@
                      , bytestring
                      , lens
                      , either
+                     , fn
   default-language:    Haskell2010
   ghc-options:         -Wall
 
diff --git a/src/Web/Fn/Extra/Heist.hs b/src/Web/Fn/Extra/Heist.hs
--- a/src/Web/Fn/Extra/Heist.hs
+++ b/src/Web/Fn/Extra/Heist.hs
@@ -23,6 +23,7 @@
                             -- * Initializer
                           , heistInit
                             -- * Rendering templates
+                          , heistServe
                           , render
                           , renderWithSplices
                             -- * Building splices
@@ -50,6 +51,7 @@
 import           Network.Wai
 import qualified Network.Wai.Util           as W
 import qualified Text.XmlHtml               as X
+import           Web.Fn
 
 -- | The type of our state. We need a ReaderT to be able to pass the
 -- runtime context (which includes the current request) into the
@@ -62,18 +64,9 @@
 type FnSplice ctxt = Splice (ReaderT ctxt IO)
 
 -- | In order to have render be able to get the 'FnHeistState' out of
--- our context, we need this helper class. The easiest way to
--- instantiate it is with the 'heistLens', but if you prefer you can
--- use 'getHeist' and 'setHeist' instead (one of these must be
--- provided).
+-- our context, we need this helper class.
 class HeistContext ctxt where
-  heistLens :: Functor f => (FnHeistState ctxt -> f (FnHeistState ctxt)) ->
-                            ctxt -> f ctxt
-  heistLens f c = setHeist c <$> f (getHeist c)
   getHeist :: ctxt -> FnHeistState ctxt
-  getHeist = view heistLens
-  setHeist :: ctxt -> FnHeistState ctxt -> ctxt
-  setHeist c r = set heistLens r c
 
 -- | Initialize heist. This takes a list of paths to template
 -- directories and a set of interpreted splices. Currently, we don't
@@ -90,6 +83,25 @@
                                     & hcLoadTimeSplices .~ defaultLoadTimeSplices
                                     & hcNamespace .~ "")
 
+-- | Render templates according to the request path. Note that if you
+-- have matched some parts of the path, those will not be included in
+-- the path used to find the templates. For example, if you have
+-- 'foo/bar.tpl' in the directory where you loaded templates from,
+--
+-- > path "foo" ==> heistServe
+--
+-- Will match @foo/foo/bar@, but not @foo/bar@. To match that, you could:
+--
+-- > anything ==> heistServe
+--
+-- If no template is found, this will continue routing.
+heistServe :: (RequestContext ctxt, HeistContext ctxt) =>
+              ctxt ->
+              IO (Maybe Response)
+heistServe ctxt =
+  let p = pathInfo . fst $ getRequest ctxt in
+  render ctxt (T.intercalate "/" p)
+
 -- | Render a single template by name.
 render :: HeistContext ctxt =>
           ctxt ->
@@ -105,7 +117,7 @@
                      Splices (FnSplice ctxt) ->
                      IO (Maybe Response)
 renderWithSplices ctxt name splices =
-  do r <- runReaderT (renderTemplate (bindSplices splices (ctxt ^. heistLens)) (T.encodeUtf8 name)) ctxt
+  do r <- runReaderT (renderTemplate (bindSplices splices (getHeist ctxt)) (T.encodeUtf8 name)) ctxt
      case first toLazyByteString <$> r of
        Nothing -> return Nothing
        Just (h,m) -> Just <$> W.bytestring status200 [(hContentType, m)] h
