Haskell web framework inspired by Ruby's Sinatra, using WAI and Warp

Version on this page:0.10.2@rev:4
LTS Haskell 22.29:0.20.1@rev:1
Stackage Nightly 2024-07-17:0.22@rev:2
Latest on Hackage:0.22@rev:2

See all snapshots scotty appears in

BSD-3-Clause licensed and maintained by Andrew Farmer
This version can be pinned in stack with:scotty-0.10.2@sha256:61ca65b6ea23012d483c01bfcadcad72674011b81b180da6787e619a653e2a98,4320

Module documentation for 0.10.2

Scotty Build StatusCoverage Status

A Haskell web framework inspired by Ruby’s Sinatra, using WAI and Warp.

{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty

import Data.Monoid (mconcat)

main = scotty 3000 $ do
    get "/:word" $ do
        beam <- param "word"
        html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"]

Scotty is the cheap and cheerful way to write RESTful, declarative web applications.

  • A page is as simple as defining the verb, url pattern, and Text content.
  • It is template-language agnostic. Anything that returns a Text value will do.
  • Conforms to WAI Application interface.
  • Uses very fast Warp webserver by default.

See examples/basic.hs to see Scotty in action. (basic.hs needs the wai-extra package)

> runghc examples/basic.hs
Setting phasers to stun... (port 3000) (ctrl-c to quit)
(visit localhost:3000/somepath)

As for the name: Sinatra + Warp = Scotty.

More Information

Tutorials and related projects can be found in the Scotty wiki:

Development & Support

Open an issue on GitHub or join #scotty on Freenode.

Copyright (c) 2012-2014 Andrew Farmer



  • Removed debug statement from routes


  • Parsable instances for Word, Word8, Word16, Word32, Word64 [adamflott]
  • Parsable instances for Int8, Int16, Int32, Int64, and Natural
  • Removed redundant Monad constraint on middleware


  • The monad parameters to ScottyT have been decoupled, causing the type of the ScottyT constructor to change. As a result, ScottyT is no longer a MonadTrans instance, and the type signatures ofscottyT, scottyAppT, and scottyOptsT have been simplified. [ehamberg]

  • socketDescription no longer uses the deprecated PortNum constructor. Instead, it uses the Show instance for PortNumber. This changes the bytes from host to network order, so the output of socketDescription could change. [ehamberg]

  • Alternative, MonadPlus instances for ActionT

  • scotty now depends on transformers-compat. As a result, ActionT now uses ExceptT, regardless of which version of transformers is used. As a result, several functions in Web.Scotty.Trans no longer require a ScottyError constraint, since ExceptT does not require an Error constraint (unlike ErrorT).

  • Added support for OPTIONS routes via the options function [alvare]

  • Add scottySocket and scottySocketT, exposing Warp Unix socket support [hakujin]

  • Parsable instance for lazy ByteString [tattsun]

  • Added streaming uploads via the bodyReader function, which retrieves chunks of the request body. [edofic]

    • ActionEnv had a getBodyChunk field added (in Web.Scotty.Internal.Types)
    • RequestBodyState and BodyPartiallyStreamed added to Web.Scotty.Internal.Types
  • jsonData uses aeson’s eitherDecode instead of just decode [k-bx]


  • text/html/json only set Content-Type header when not already set


  • Add charset=utf-8 to Content-Type for text, html and json

  • Assume HTTP status 500 for defaultHandler

  • Remove deprecated source method.

  • No longer depend on conduit.


  • Bump aeson upper bound

  • Fix mtl related deprecation warnings


  • Export internal types

  • Added MonadBase, MonadTransControl and MonadBaseControl instances for ActionT


  • Upgrade to wai/wai-extra/warp 3.0

  • No longer depend on conduit-extra.

  • The source response method has been deprecated in favor of a new stream response, matching changes in WAI 3.0.

  • Removed the deprecated reqHeader function.


  • Bump upper bound for case-insensitive, mtl and transformers.


  • Bump lower bound on conduit, add conduit-extra to cabal build depends.


  • Default warp settings now use setFdCacheDuration 0 to work around a warp issue where file changes are not getting picked up.


  • Renamed reqHeader to header. Added headers function to get all headers.

  • Changed MonadIO instance for ActionT such that IO exceptions are lifted into ScottyErrors via stringError.

  • Make Bool parsing case-insensitive. Goal: support both Haskell’s True/False and Javascript’s true/false. Thanks to Ben Gamari for suggesting this.

  • Bump aeson/text upper bounds.

  • Bump wai/wai-extra/warp bounds, including new lower bound for warp, which fixes a security issue related to Slowloris protection.


  • Bump upper bound for text.


  • Match changes in wai-extra.


  • The Scotty transformers (ScottyT and ActionT) are now parameterized over a custom exception type, allowing one to extend Scotty’s ErrorT layer with something richer than Text errors. See the exceptions example for use. ScottyM and ActionM remain specialized to Text exceptions for simplicity.

  • Both monads are now instances of Functor and Applicative.

  • There is a new cookies example.

  • Internals brought up-to-date with WAI 2.0 and related packages.


  • The Scotty monads (ScottyM and ActionM) are now monad transformers, allowing Scotty applications to be embedded in arbitrary MonadIOs. The old API continues to be exported from Web.Scotty where:

      type ScottyM = ScottyT IO
      type ActionM = ActionT IO

    The new transformers are found in Web.Scotty.Trans. See the globalstate example for use. Special thanks to Dan Frumin (co-dan) for much of the legwork here.

  • Added support for HTTP PATCH method.

  • Removed lambda action syntax. This will return when we have a better story for typesafe routes.

  • reqHeader :: Text -> ActionM Text ==> reqHeader :: Text -> ActionM (Maybe Text)

  • New raw method to set body to a raw ByteString

  • Parse error thrown by jsonData now includes the body it couldn’t parse.

  • header split into setHeader and addHeader. The former replaces a response header (original behavior). The latter adds a header (useful for multiple Set-Cookies, for instance).