Spock is a Haskell web framework where the type of a route is part of the route
Another Haskell web framework for rapid development
At a glance
- What is it?
- agrafix/Spock is a Haskell web framework for rapid development whose routing is typesafe by default, with sessions, CSRF protection, typed JSON APIs and OpenAPI generation, and a package family that includes browser and server sharing in Haskell. Its Hackage releases stop in 2017 while the repository was pushed in October 2026, so the interesting question is which channel you install from.
- Who is it for?
- Adopt Spock if you are writing a Haskell web service and want the compiler to reject a request that does not match your handler's type, because typesafe routing is the idea the framework is built around and everything else, from typed contexts to typed JSON APIs, extends it.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 23 days ago.
- What is it written in?
- Mainly Haskell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Typesafe routing is the reason the framework exists
The description is a modest one, another Haskell web framework for rapid development, and the feature list is where the design shows. Fast typesafe routing sits at the top, followed by middleware, request IDs and structured logging, JSON, sessions, cookies, a database helper, CSRF protection, typesafe contexts, typed JSON APIs with OpenAPI generation, and shared Haskell browser and server applications. Almost every item is a variation on the same idea, that the type system should carry information about the request all the way into the handler. A typesafe context means the handler knows what is in the context. A typed JSON API means the JSON type and the route agree. The headers for typed browser routes and History API navigation extend the same approach to the client side, which is why the framework can share Haskell between the browser and the server.
Routing lives in its own package, and the untyped path is still there
The implementation detail that explains the framework's shape is in the Notes section. Since version 0.7.0.0 Spock supports typesafe routing, and if you wish to continue using the untyped version of Spock you can use Web.Spock.Simple, with the implementation of the routing in a separate Haskell package called reroute. That repository listing includes a reroute directory at the top level, so the router is a project in its own right with its own benchmark, and the README notes that the Cabal project enables all native libraries, tests and the routing benchmark, runnable with cabal bench reroute. The other note is a change in behaviour you should know about. Since version 0.11.0.0 Spock drops simple routing in favor of typesafe routing and drops safe actions in favor of the usual way of CSRF protection with a token. So the untyped module is the old world, and it is still there, but the framework has moved on.
Sessions in the database or in an encrypted cookie
Session handling is one area where the framework is deliberately modular, with two optional packages in the repository, Spock-session-postgresql and Spock-session-cookie, described in the feature list as optional persistent PostgreSQL sessions and optional encrypted cookie sessions. The difference in approach is the usual one. A PostgreSQL session store keeps server side state, which means the server can revoke a session, and it means the application needs a database. An encrypted cookie session keeps the state in the client, signed and encrypted, which means no extra infrastructure and no revocation, and the secret used to encrypt becomes a piece of your deployment that has to be protected. Which one you want depends on whether logout has to be immediate and whether you already run a database. The rest of the session machinery, including the general sessions feature and cookie handling, is in the core package, and there is a separate session soak benchmark for retention and HTTP performance investigations.
File uploads, grouped by field, with a documented lifetime
The README documents the upload API with a small example, and the detail that matters is in the surrounding prose:
uploads <- filesMulti
let documents = HM.lookupDefault [] "documents" uploadsThe function filesMulti retrieves every uploaded file, grouped by form field name, so an input element with name documents and multiple set can be read that way. HM is Data.HashMap.Strict. Each list preserves upload order, and each UploadedFile provides its name, content type and temporary location. The last sentence is the operational detail: process or copy the temporary files during the request, because they are removed when it finishes. That is a sharp edge, because a handler that queues the path for later processing will find the file gone, and the README also notes that the existing files function continues to return the last file for each field, which is the behaviour most code written against the older API expects.
HTTPS is either a proxy in front or a conversion to a WAI app
The framework does not serve TLS itself, and the README gives two options. The first is to use nginx, haproxy or something similar as a reverse proxy in front of the Spock application, which keeps TLS termination in infrastructure you already operate. The second is to convert the Spock application to a wai application using spockAsApp and then use the warp-tls package to run it, which puts the certificate and the TLS termination inside the Haskell process. The difference in approach matters for how you operate it. The proxy arrangement keeps one TLS configuration for all your services and lets the application speak plain HTTP, but it adds a hop and a component to debug. The warp-tls route is a single process with no extra moving part, at the cost of managing certificates in the application deployment and losing the simplicity of a uniform proxy layer. Which is better depends on whether your organisation already terminates TLS at a proxy for everything else.
The build is GHC 9.14.1 with Cabal, and Stack is supported too
The Hacking section is unusually complete, and it is the part a contributor needs. The native packages use GHC 9.14.1, installed with GHCup, along with Cabal 3.16.0.0 or newer, and CI uses 3.18.1.0:
ghcup install ghc 9.14.1
ghcup set ghc 9.14.1
ghcup install cabal 3.18.1.0
ghcup set cabal 3.18.1.0
cabal update
cabal build all
cabal test all --test-show-details=directStack 3.11.1 is also supported, with stack.yaml pinning the package versions and overriding the compiler with GHC 9.14.1, and stack.yaml.lock recording the resolved dependencies:
stack build --test --bench --no-run-tests --no-run-benchmarks
stack test -j 1The repository carries several stack variants, stack-cookie.yaml, stack-postgresql.yaml, stack-tutorials.yaml and the main stack.yaml, and matching cabal.project files including cabal.project.javascript and a frozen one for the browser packages, so a contributor can build a subset rather than the whole tree. There is also a hie.yaml for IDE support and a scripts directory. The benchmark story is taken seriously enough to have two dedicated locations, a benchmarks directory for HTTP comparisons and a session soak benchmark, plus the reroute routing benchmark.
A package family, not a single package
The repository layout shows the framework as a family of packages. Spock is the main package, Spock-core holds the shared core with the request IDs and structured logging, Spock-api carries the typed JSON APIs and OpenAPI generation, Spock-api-server and Spock-api-ghcjs are the server and JavaScript backend variants, Spock-browser is the typed browser routes and History API navigation, and the two session packages sit alongside. A separate reroute package carries the routing. The examples directory is organised by topic, with browser, cookbook, rendering, rest-api and security examples. There is also a wider ecosystem around it, and the README lists extensions such as Spock-worker for background workers, Spock-digestive for digestive functors and Spock-lucid for Lucid templates, along with packages it works well with, including users for user management and validate-input for data validation. The API reference, the tutorial, a REST API tutorial and blog posts on type-safe routing and on authentication are all linked from the README.
The published package and the repository are a decade apart
The maintenance picture needs two dates. The Hackage releases are old: 0.10.0.1 on 2015-11-11, 0.11.0.0 on 2016-09-02 and 0.12.0.0 on 2017-02-03. The repository, on the other hand, is not archived and its last push was on 2026-10-01, with a build badge, a GHC 9.14.1 toolchain and a JavaScript backend targeting GHC's own compiler rather than the historical ghcjs, whose configuration file has been replaced by cabal.project.javascript. The browser example installs a pinned GHC JavaScript 9.12.2 with Emscripten and CI runs the compiled client in Chromium. The licence is BSD3, with the copyright line naming Alexander Thiemann for 2013 to 2021, and the contributing section states that sending a pull request means agreeing to have the contribution released under the BSD3 License as part of the Spock package or related packages. So the code is current and the Hackage metadata is not, and which one your build resolves is the question to settle first.
Editorial conclusion
Adopt Spock if you are writing a Haskell web service and want the compiler to reject a request that does not match your handler's type, because typesafe routing is the idea the framework is built around and everything else, from typed contexts to typed JSON APIs, extends it. Do not adopt it on the assumption that the published package is the current code, because the newest Hackage release is 0.12.0.0 from 2017 while the repository moves on GHC 9.14.1, so check which channel you are building from. Before you start, read the API reference for the route and session APIs you intend to use, and decide whether you want the typed routing or the older untyped module.
Frequently asked questions
What does Spock give a Haskell web application?
The README lists fast typesafe routing, middleware, request IDs and structured logging, JSON, sessions, cookies, a database helper, csrf-protection, typesafe contexts, typed JSON APIs with OpenAPI generation, and shared Haskell browser and server applications, with optional PostgreSQL session storage and optional encrypted cookie sessions.
How do I retrieve multiple uploaded files in Spock?
Use filesMulti, which returns every uploaded file grouped by form field name, so a lookup with HM.lookupDefault gives you the list for that field. Each UploadedFile carries its name, content type and temporary location, and the temporary files are removed when the request finishes, so they have to be processed or copied during the request.
Can I serve a Spock application over HTTPS?
Yes, in two ways according to the README. Put nginx, haproxy or a similar reverse proxy in front of the application, or convert it to a wai application with spockAsApp and run it with the warp-tls package.
How is the Spock project built and tested?
The native packages use GHC 9.14.1 with Cabal 3.16.0.0 or newer, and the README gives the ghcup install sequence followed by cabal build all and cabal test all. Stack 3.11.1 is also supported, with stack.yaml pinning the snapshot and stack.yaml.lock recording the resolved dependencies.
Is the typesafe routing the only way to write routes in Spock?
No, though it is the default direction. Since version 0.7.0.0 Spock supports typesafe routing, and the untyped version remains available through Web.Spock.Simple, with the routing implementation in a separate package called reroute. Since version 0.11.0.0 the simple routing and safe actions were dropped in favour of typesafe routing and the usual token based CSRF protection.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/agrafix-spock)Was this useful?