Gleam is a type safe and scalable language for the Erlang virtual machine and JavaScript runtimes. Today Gleam v0.31.0 has been released, let’s take a look at what’s new.

Requiring explicit dependencies

A Gleam application’s dependency graph contains no duplicate packages, each package has exactly one version.


Here the application has specified library_a as a dependency in its gleam.toml, and library_a has specified library_b as a dependency in its own gleam.toml.

As there’s no ambiguity as to what version to use Gleam has historically allowed importing modules from packages that you don’t directly depend upon. The application could happily import modules from library_b.

Over time we have learnt that this form of indirect dependency is unclear and confusing to a lot of folks, so we’re moving to making dependencies explicit and only permitting imports from direct dependencies.

With this release Gleam will now emit a warning when importing modules from a package your application does not directly depend upon, and in future versions of Gleam this will become an error.

warning: Transative dependency imported
  ┌─ src/app.gleam:2:1
2 │ import mist
  │ ^^^^^^^^^^^

The module `mist` is being imported, but `mist`, the package it belongs to,
is not a direct dependency of your package.
In a future version of Gleam this may become a compile error.

Run this command to add it to your dependencies:

    gleam add mist

Marking functions as deprecated

The @deprecated("...") attribute has been added to allow marking functions as deprecated.

If a deprecated function is used Gleam will emit a warning during compliation, informing the programmer that they need to update their code.

pub fn main() {

@deprecated("This function is not good! Use `new_function` instead, it is better.")
fn deprecated_function() {
  // Inset implemenation here...
warning: Deprecated value used
  ┌─ /Users/louis/Desktop/thingy/src/thingy.gleam:2:3
2 │   deprecated_function()
  │   ^^^^^^^^^^^^^^^^^^^ This value has been deprecated

It was deprecated with this message: This function is not good! Use
`new_function` instead, it is better.

Quality of life improvements

As we’re now ramping up to version 1.0 we’re making lots of small improvements to the ergonomics of the language.

The record access syntax ( can now be used in case clause guard expressions.

pub fn listed(names: List(String), person: Person) -> String {
  case names {
    [name, ..names] if name == -> True
    [_, ..names] -> listed(names, person)
    [] -> False

The as keyword can now be used to assign the prefix of a string to a variable when pattern matching.

pub fn parse_tag(tag: String) -> Result(Tag, Nil) {
  case tag {
    "category " as key <> value
    | "region " as key <> value
    | "priority " as key <> value -> {
      let key = string.trim(key)
      Ok(Tag(key, value))
    _ -> Error(Nil)

And the standard library gleam/int module now has a series of functions for performing bitwise operations.

int.bitwise_and(9, 3)
// -> 1

int.bitwise_or(9, 3)
// -> 11

int.bitwise_exclusive_or(9, 3)
// -> 10

// -> -3

int.bitwise_shift_left(1, 2)
// -> 4

int.bitwise_shift_right(1, 2)
// -> 0


Gleam has been used to make backend web applications for a good few years, but without a helpful web framework the programmer has to feel comfortable piecing together various packages to build their application.

Most folks are not so interested in the nitty-gritty of how to put together a web application and want to focus on the business logic of their application, so the Wisp framework has been created to help folks get on with solving problems with Gleam.

Wisp takes the lessons learnt from various existing Gleam web applications and web frameworks in other languages, and provides a practical, type safe, and magic-free experience for building web applications. A Wisp request handler looks a like this:

import gleam/result.{try}
import my_app/people
import my_app/web.{Context}
import wisp.{Request, Response}

pub fn handle_request(req: Request, ctx: Context) -> Response {
  use json <- wisp.require_json(req)

  let result = {
    use params <- try(people.parse_params(json))
    use person <- try(, ctx.db))

  case result {
    Ok(body) -> wisp.json_response(body, 201)
    Error(_) -> wisp.bad_request()

Today Wisp has a small feature set similar to that of Ruby’s Sinatra or Python’s Flask, but it is expected to grow over time to include more features as the maintainers and community decides what is useful and how they should work.

Wisp is not a Gleam-core project like the compiler or the standard library, but I (Louis Pilfold, Gleam’s creator) am the primary maintainer of Wisp, and the framework has been designed with the help of prominent members of the Gleam community.

Check out the website and the source code if you’d like to learn more. 🧚


Gleam is made possible by the support of all the kind people and companies who have very generously sponsored or contributed to the project. Thank you all!

If you like Gleam consider sponsoring or asking your employer to sponsor Gleam development. I work full time on Gleam and your kind sponsorship is how I pay my bills!

Thanks for reading! Happy hacking! 💜