Kemal is a Fast, Effective, Simple web framework written in Crystal.

Hello everyone,

Kemal 0.24.0 is here :tada:

This release brings support for Crystal 0.26.0 and adds new features. There are also some breaking changes.

New and Shiny Exception Page :star:

Thanks to the awesome exception_page shard, we got a new and shiny exception page implemented by @mamantoha :pray:

new exception page

Custom Port Bindings :tada:

You can now bind a single Kemal server to multiple ports. Thanks to @straight-shoota :pray: do |config|
  server = config.server.not_nil!
  server.bind_tcp "", 3000
  server.bind_tcp "", 3001

Breaking changes :hammer:

  • Removed env.params.files. You can use Crystal’s built-in HTTP::FormData.parse instead
post "/upload" do |env|
  HTTP::FormData.parse(env.request) do |upload|
    filename = file.filename

    if !filename.is_a?(String)
      "No filename included in upload"
      file_path = ::File.join [Kemal.config.public_folder, "uploads/", filename], "w") do |f|
      IO.copy(file.tmpfile, f)
    "Upload OK"
  • From now on to access dynamic url params in a WebSocket route you have to use:
ws "/:id" do |socket, context|
  id = context.ws_route_lookup.params["id"]
  • Removed _method magic param from env.params.body.

Thanks for using and supporting Kemal. You can check the full CHANGELOG here.

P.S: You can support Kemal development via Patreon :pray:

Happy Crystalling :heart: