Framework
gleam-wisp/wisp avatar
gleam-wisp/wisp

Wisp Gleam Web Framework: Handlers, Middleware, and Static Files

🧚 A practical web framework for Gleam

1,491 stars75 forksGleamApache-2.0

At a glance

What is it?
Wisp is a Gleam web framework built around request handlers and composable middleware. It fits developers who want direct HTTP functions and explicit application structure, but its README leaves installation and runtime setup undocumented.
Who is it for?
Adopt Wisp when the application is written in Gleam and its handler-plus-middleware model fits the project. Do not choose it for an extensive built-in feature list, because the README documents only a small core.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 16 days ago.
What is it written in?
Mainly Gleam, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 15, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Wisp's Request Handler Model for Gleam Applications

Wisp addresses the mechanics of receiving HTTP requests and producing HTTP responses in a Gleam application. Its primary abstraction is a handler: a function that accepts an HTTP `Request` and returns an HTTP `Response`. The framework does not force routing or application state into a separate object in the documented example. A handler can instead accept an application-defined `Context` alongside the request.

That distinction matters when choosing a web framework. The README presents Wisp as a collection of practical Gleam functions rather than a full application scaffold. Developers remain responsible for organizing routes and application logic according to the conventions of their own project. The README does not document a router, controller base type, schema validator, database integration, session implementation, or deployment command.

The context example contains a `secret` field, but the README does not explain how that value is populated or used. It only demonstrates that state such as a database connection or user session can be passed to a handler. This approach gives application code control over state, although it also leaves connection creation, lifecycle management, and state access to the application unless separate API documentation covers those details.

How Wisp Middleware Wraps Gleam Responses

Wisp's second core concept is middleware. According to the README, middleware receives a response-returning function as its last argument and returns a response. This continuation shape lets behavior wrap the work that produces an HTTP response. Handlers and the functions passed to middleware may also accept application-defined arguments, so the composition model is not limited to `Request` and `Response` types.

The documented handler uses Gleam's `use` syntax to apply request logging and static file serving. Logging is attached first in source order, followed by `serve_static`. The final expression is `wisp.ok()`, which supplies a response if the preceding middleware does not handle the request. Gleam's indentation-based `use` expression makes the chain visible directly in the application code.

Middleware ordering is a design concern. A middleware function can produce a response without invoking the continuation it receives. As a result, one function can stop later application handling, including when it serves a matching static file. The README identifies the middleware roles but does not specify every ordering rule, early-response convention, or error behavior. HexDocs needs to be checked before combining middleware whose interactions are not apparent from their names.

Wisp Request Handling with Application Context

A minimal documented handler imports Wisp's request and response types, declares a local context type, and returns `wisp.ok()`. The `Request` parameter identifies the incoming HTTP request, while `Context` demonstrates that application state can accompany it. The repository's primary language is Gleam, and `gleam.toml` is present at the top level, but the README does not provide a complete runnable project around this function.

The README shows the following handler:

gleam
import wisp.{type Request, type Response}

pub type Context {
  Context(secret: String)
}

pub fn handle_request(request: Request, context: Context) -> Response {
  wisp.ok()
}

This establishes the function signature but intentionally does not perform routing or access `context`. A complete application needs code that creates the context, dispatches requests to the appropriate handler, and connects that handler to a supported server adapter. The repository includes `wisp_mist` and `wisp_ewe`, which suggest separate runtime integrations, but the README does not explain their configuration or startup requirements. A reader should consult the repository files and HexDocs rather than assume a server command or runtime target.

Wisp Request Logging and Static File Handling

The README gives one concrete middleware example. `log_request` logs a message for each handled request, while `serve_static` serves static resources such as images and CSS. The handler still ends with `wisp.ok()`, giving the middleware chain a fallback response.

The documented application code is:

gleam
import wisp.{type Request, type Response}

pub fn handle_request(request: Request) -> Response {
  use <- wisp.log_request(request)
  use <- wisp.serve_static(request, under: "/static", from: "/public")
  wisp.ok()
}

The public request path in this example is `/static`, while files are read from `/public`. The README does not document cache headers, content type selection, directory traversal protection, missing-file responses, or whether `under` accepts only a single path segment. Those details should be checked in the API documentation before static serving handles uploaded files or files outside the developer's direct control.

This example shows Wisp's composition style. A developer can add request logging or static file handling without wrapping the entire function in a framework-specific object. The trade-off is that middleware ordering and continuation behavior must be understood directly, especially when one function may produce the final response without calling the next function.

Starting with Wisp Examples and HexDocs

The README directs new users to the repository's `examples` directory and says the examples cover various scenarios, include comments, and contain tests. It also links to HexDocs for the API reference. The README does not give a package installation command, executable name, server port, environment variable, or startup command, so this review does not invent one.

The repository layout confirms that the example area contains `examples/gleam.toml`, `examples/src/`, `examples/test/`, and `examples/priv/`. A new user can start by opening the example project and reviewing its configuration. The README does not say whether all examples use the same runtime integration or whether Wisp can run on multiple Gleam targets.

For a first real use, the documented sequence is limited but concrete. Open the examples, choose one that matches the intended runtime, identify the handler registration code, and inspect the middleware used by that handler. The README does not document a startup command. The project documentation site and HexDocs are the appropriate next sources for installation, server adapters, and API details that are absent from the README.

The README also names `gleam-lang/packages` as an open source Wisp application deployed to Fly.io. That is evidence of a real application usage, not a complete deployment guide. Its SQLite, LiteFS, and Fly.io arrangement should not be assumed to be required by Wisp itself.

Wisp Design Trade-offs and Apache-2.0 Implications

Wisp's documented scope is compact: handlers turn requests into responses, middleware wraps those handlers, and application-defined context can carry state. Compared with a convention-heavy web framework that supplies a defined router, controller lifecycle, validation layer, and generated application structure, Wisp leaves more application organization to the developer. That is a difference in approach, not evidence that either approach is better.

It may be the wrong tool when a team requires routing, validation, sessions, and integration conventions to be standardized by the framework itself. The README does not establish that Wisp supplies those features. It is also a poor fit for a project committed to another primary language unless the team has already accepted the work required to connect Wisp's Gleam interfaces to that system.

The repository is not archived, and its last push was on 2026-10-07. The listed releases include `v2.2.2` and `v2.2.1` on 2026-03-27, plus `v2.2.0` on 2026-01-16. Those dates show recent release activity, but the README does not define a compatibility policy or upgrade procedure. An adopter should review `CHANGELOG.md` before changing versions and confirm whether handler or middleware APIs differ between releases.

The project uses the Apache-2.0 licence. Teams should inspect the repository's `LICENCE` file for the exact terms and notices that apply to their distribution. Dependency licences also need separate review. This is a compliance check, not legal advice, and the README does not offer project-specific licence exceptions.

Editorial conclusion

Adopt Wisp when the application is written in Gleam and its handler-plus-middleware model fits the project. Do not choose it for an extensive built-in feature list, because the README documents only a small core. Before adoption, verify the Hex installation procedure, runtime integration through `wisp_mist` or `wisp_ewe`, static asset behavior, middleware ordering, and Apache-2.0 obligations. The first decision should be whether explicit handler composition fits the application better than a more prescriptive framework.

Frequently asked questions

How are HTTP handlers defined in Wisp?

A handler accepts a Wisp `Request` and returns a `Response`. It may also accept an application-defined context containing state such as a database connection or session.

How does middleware work in Wisp?

Middleware accepts a response-returning function as its last argument and returns a response. The README demonstrates applying `log_request` and `serve_static` with Gleam's `use` syntax.

How do I serve static files with Wisp?

The documented call is `wisp.serve_static(request, under: "/static", from: "/public")`. The README does not document caching, content type selection, or missing-file behavior.

Official sources

  1. gleam-wisp/wisp on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/gleam-wisp-wisp.svg)](https://hysenlabs.com/projects/gleam-wisp-wisp)