<!--
  SPDX-License-Identifier: Apache-2.0
  SPDX-FileCopyrightText: 2020 The Gleam contributors
-->

# Changelog

## v1.17.0 - 2026-06-02

The release is dedicated to the memory of Chris Young, a man who inspired and
believed in people. Without him, Gleam may not have ever existed.

### Bug Fixes

- Restrict custom documentation page `path` and `source` values so `gleam docs
  build` cannot escape the docs output directory or project root.
  ([evipepota](https://github.com/evipepota) and
  [Louis Pilfold](https://github.com/lpil))

- Stricter deserialisation rules for files internal the build directory to
  reject corrupted data.
  ([Abdelrahman Ahmed Aboelkasem](https://github.com/0x2face),
  [Aly](https://github.com/spect3r1), and
  [Louis Pilfold](https://github.com/lpil))

- Restrict publication tarball creation so they cannot contain files from
  outside the project root.
  ([Abdelrahman Ahmed Aboelkasem](https://github.com/0x2face),
  [Aly](https://github.com/spect3r1), and [Louis Pilfold](https://github.com/lpil))

## v1.17.0-rc2 - 2026-06-01

### Bug Fixes

- Fixed a bug where the "Convert to case" code action would silently fail for
  every inexhaustive `let` assignment in a module other than the first one.
  ([John Downey](https://github.com/jtdowney))

- Fixed a bug where the JavaScript code generator would not emit semicolon
  after some expressions.
  ([Andrey Kozhev](https://github.com/ankddev))

- Fixed a bug where the JavaScript prelude's `BitArray$BitArray$data` FFI
  function would throw an Error using the wrong class.
  ([John Downey](https://github.com/jtdowney))

- Fixed a bug where the JavaScript code generator could produce duplicate `let`
  declarations for internal variables when a `case` expression was used as a
  step in a pipeline.
  ([Eyup Can Akman](https://github.com/eyupcanakman))

- Fixed a bug where the JavaScript code generator would use wrong constructor
  name in equality comparisons for imported variant with zero arguments and
  import alias.
  ([Andrey Kozhev](https://github.com/ankddev))

## v1.17.0-rc1 - 2026-05-23

### Compiler

- The compiler now suggest public values from imported modules when the variable
  is unknown. These values are suggested based on name and arity.

  Considering this program:

  ```gleam
  import gleam/io

  pub fn main() -> Nil {
    println("Hello, World!")
  }
  ```

  The compiler will display this error message:

  ```text
    error: Unknown variable
    ┌─ /path/to/project/src/project.gleam:4:3
    │
  4 │   println("Hello, World!")
    │   ^^^^^^^

  The name `println` is not in scope here.
  Did you mean one of these:

      - io.println
  ```

  ([raphrous](https://github.com/realraphrous))

- The inference of record update expressions is now more fault tolerant: if
  there's an error in the record being updated, the compiler can still able to
  analyse the fields that are being provided.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- The inference of clause guards is now more fault tolerant: if there's an error
  in a part of the guard expression, the compiler can still able to analyse the
  rest of the guard rather than stopping at the first error.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- It is now possible to use the `todo` keyword in constants, this will result in
  an helpful error message rather than a syntax error.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- The compiler now prints correctly qualified or aliased type names when
  printing warnings. For example:

  ```gleam
  import user

  pub fn main() {
    user.to_string(todo)
    |> io.println
  }
  ```

  Will produce the following warning:

  ```
  warning: Todo found
    ┌─ /src/warning/wrn.gleam:4:19
    │
  4 │     user.to_string(todo)
    │                    ^^^^ This code is incomplete

  This code will crash if it is run. Be sure to finish it before
  running your program.

  Hint: I think its type is `user.User`.
  ```

  Notice how the type hint is correctly qualified for the module the warning is
  raised in.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- When writing a constant record with an empty arguments list the compiler will
  no longer stop to analyse the entire module.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- The compiler now normalizes remaining-bytes bit-array checks for the
  JavaScript backend so `(bitSize - c) % 8 === 0` becomes `bitSize % 8 === 0`
  when the constant offset `c` is congruent modulo 8. This produces more uniform
  generated code for byte-aligned patterns.
  ([Daniele Scaratti](https://github.com/lupodevelop))

- The code generated for destructuring exhaustive patterns with `let` is now
  less verbose on the JavaScript target.

  ([Gavin Morrow](https://github.com/gavinmorrow))

### Build tool

- The `gleam dev` command now accepts the `--no-print-progress` flag. When this
  flag is passed, no progress information is printed.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Tables in the generated docs now look better on smaller screens.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- The comment in `manifest.toml` now instructs the user to include it in their
  source control repository.
  ([Louis Pilfold](https://github.com/lpil))

- The `gleam deps outdated` command now always prints a summary showing how many
  packages have newer versions available. For example:

  ```txt
  $ gleam deps outdated
  1 of 12 packages have newer versions available.

  Package       Current  Latest
  -------       -------  ------
  gleam_stdlib  0.70.0   0.71.0
  ```

  When no packages are outdated, only the summary line is printed:

  ```txt
  $ gleam deps outdated
  0 of 12 packages have newer versions available.
  ```

  ([Daniele Scaratti](https://github.com/lupodevelop))

- The package manager now has a specific error and automatic re-authentication
  flow for when a Hex session has been revoked or has expired.
  ([Sahil Upasane](https://github.com/404salad))

- New packages are created requesting Erlang/OTP version 29 on GitHub actions.
  ([Louis Pilfold](https://github.com/lpil))

- `gleam publish` will now better discover Git repository in monorepos. This
  improves suggestions to push a tag, if it doesn't exist.
  ([Andrey Kozhev](https://github.com/ankddev))

- The `gleam export escript` command has been added for the creation of
  [escripts](https://www.erlang.org/doc/apps/erts/escript_cmd.html), BEAM
  programs bundled into a single file.
  ([Louis Pilfold](https://github.com/lpil))

### Language server

- The language server now offers a "Fill labels" code action on constants to
  automatically fill in the missing labelled arguments from a record
  constructor. For example:

  ```gleam
  pub type Pokemon {
    Pokemon(number: Int, name: String, hp: Int)
  }

  pub const cleffa = Pokemon(number: 173)
  ```

  In this code snippet we haven't specified the `name` and `hp` fields, that's
  an error! Triggering the "Fill labels" code action will result in the
  following:

  ```gleam
  pub const cleffa = Pokemon(number: 173, name: todo, hp: todo)
  ```

  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- When hovering a record update expression, the language server can now show the
  fields that are not being updated. For example:

  ```gleam
  pub type Person {
    Person(name: String, age: Int)
  }

  pub fn happy_birthday_mom() {
    let mom = Person(name: "Antonella", age: 60)
    Person(..mom, age: 61)
    //     ^^^^^ Hovering this will show:
    //           Unchanged fields:
    //           - name
  }
  ```

  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- The language server can now help with completions when typing a list's tail:

  ```gleam
  pub fn main() {
    let things_i_like = ["Gleam", "Ice Cream"]
    ["Dogs", ..t|]
    //          ^ Can now suggest a completion for `things_i_like`
  }
  ```

  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- The language server can now help with completions when typing a record update:

  ```gleam
  pub type User {
    User(name: String, likes: List(String))
  }

  pub fn set_name(user: User, name: String) -> User {
    User(..u|)
    //      ^ Can now suggest a completion for `user`
  }
  ```

  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- The language server now has a code action to remove a redundant record update.
  For example:

  ```gleam
  pub type User {
    User(name: String, likes: List(String))
  }

  pub fn main() {
    let lucy = User(name: "Lucy", likes: ["Gleam", "Ice Cream"])
    let jak = User(..lucy, name: "Jak", likes: ["Gleam", "Dogs"])
    //             ^^^^^^ This record update is not needed!
  }
  ```

  This record update is not actually needed and will raise a warning, all fields
  are already specified. Triggering the code action anywhere on the expression
  will remove the unnecessary update:

  ```gleam
  pub type User {
    User(name: String, likes: List(String))
  }

  pub fn main() {
    let lucy = User(name: "Lucy", likes: ["Gleam", "Ice Cream"])
    let jak = User(name: "Jak", likes: ["Gleam", "Dogs"])
  }
  ```

  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- When using the wrong operator in a guard, the language server can now suggest
  and apply an automatic fix. For example:

  ```gleam
  pub fn categorise() {
    case pokemon {
      Pokemon(name:, ..) if name == "rai" + "chu" -> todo
      _ -> todo
    }
  }
  ```

  Gleam has no operator overloading, and the operator used to join strings is
  `<>`, not `+`. The language server can automatically fix this common mistake.
  Triggering the code action on the guard will replace `+` with `<>`.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- The language server now presents quick fix code actions before refactoring
  ones.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- The language server now allows to further pattern match on a discard by
  replacing it with the patterns it is discarding.
  For example:

  ```gleam
  pub fn list_names(x: Result(List(String), Nil)) {
    case x {
      Error(Nil) -> io.println("no names")
      Ok(_) -> todo
      // ^ Triggering the code action here
    }
  }
  ```

  Triggering the code action will result in the following code:

  ```gleam
  pub fn list_names(x: Result(List(String), Nil)) {
    case x {
      Error(Nil) -> io.println("no names")
      Ok([]) -> todo
      Ok([first, ..rest]) -> todo
    }
  }
  ```

  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- The "Generate variant" code action now automatically adds an import to use the
  generated variant if it is generated in a module from the different one.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- The language server no longer shows completions for deprecated values from
  dependencies.
  ([Andrey Kozhev](https://github.com/ankddev))

- The language server now offers a code action to create unknown modules
  when an import is added for a module that doesn't exist.
  For example, if `import wobble/woo` is added to `src/wiggle.gleam`,
  then a code action to create `src/wobble/woo.gleam` will be presented
  when triggered over `import wobble/woo`.
  ([Cory Forsstrom](https://github.com/tarkah))

- The language server now supports finding references when triggered on an
  aliased import. For example, in the following snippet, moving the cursor
  over `log` and triggering "find references" will show all references of
  `io.println()`.

  ```gleam
  import gleam/io.{println as log}
  fn main() {
    log("Hello, world!")
  //^^^ trigger here
  }
  ```

  ([Gavin Morrow](https://github.com/gavinmorrow))

- The language server now supports `textDocument/documentHighlight` anywhere
  that `textDocument/references` is available.

  For example, triggering it with the cursor over any instance of `vec` will
  result in all of the instances of it being highlighted.

  ```gleam
  fn to_cartesian(vec) {
  //              ^^^
    let x = vec.rho * cos(vec.theta)
    //      ^^^           ^^^
    let y = vec.rho * sin(vec.theta)
    //      ^^^           ^^^
    #(x, y)
  }
  ```

  ([Gavin Morrow](https://github.com/gavinmorrow))

### Formatter

### Releases

- A `gleam-licences.html` is now included with each release, detailing the
  licences of the used dependencies.
  ([Louis Pilfold](https://github.com/lpil))

### Bug fixes

- Fixed a bug where `gleam remove` would fail with a confusing File IO error
  if `manifest.toml` didn't exist yet (e.g. in a freshly-created project or
  after the manifest had been deleted).
  ([Charlie Tonneslan](https://github.com/c-tonneslan))

- Fixed a bug where the build tool would check for new major versions of a local
  or git dependency on Hex when running `gleam update`.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the "pattern match on value" code action would generate
  invalid code when used on a `let` assignment on the right hand side of another
  `let` assignment.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the compiler wouldn't track the minimum required version
  when using list prepending in constants.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the language server wouldn't let one extract record
  constructors as variables.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the language server would suggest completions for values
  from the language's prelude, even though their types were incompatible with
  the current context.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the language server would suggest the "wrap in anonymous"
  code action even when not hovering directly over a function.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the language server would suggest the "wrap in anonymous"
  code action when hovering over a record update.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the compiler would generate invalid code for guards using
  lists with a tail.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the language server would suggest the "convert to case" code
  action even when not explicitly hovering an inexhaustive let assignment.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the language server would suggest the "add missing pattern"
  code action even when not explicitly hovering an inexhaustive case expression.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the language server would suggest the "unqualify" code
  action even when not explicitly hovering a qualified value.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the language server would suggest the "qualify" code
  action even when not explicitly hovering an unqualified type or constructor.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the language server would suggest the "generate dynamic
  decoder" code action even when not explicitly hovering a custom type.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the language server would suggest the "generate json
  encoder" code action even when not explicitly hovering a custom type.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the language server would suggest the "missing type
  parameter" code action even when not explicitly hovering a custom type.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the language server would suggest the "unwrap anonymous
  function" code action even when not explicitly hovering a custom type.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the language server would suggest the "extract function"
  code action even when selecting multiple branches of a case expression, or
  patterns and guards of a case arm.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the compiler would not warn for ints over the safe
  JavaScript limit in `BitArray` segments with a unit option.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where the compiler would incorrectly warn for ints over the
  safe JavaScript limit in `BitArray` byte segments that aren't ints.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a confusing error message when writing a constant bit array with a size
  that is not a literal number.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a confusing error message when writing bit arrays with an invalid unit.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a confusing error message when writing a constant bit array with an
  invalid segment.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a confusing error message when writing `@external` or `@deprecated`
  annotations with arguments that are not string.
  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Fixed a bug where enabling `javascript.typescript_declarations` or
  `javascript.source_maps` wouldn't generate their additional files unless the
  build directory was manually deleted. The compiler now automatically rebuilds
  the project when this configuration changes.
  ([daniellionel01](https://github.com/daniellionel01))

- Fixed a bug where using the `bytes` and `unit` options together on a bit array
  segment could generate incorrect code on the JavaScript target.
  ([Surya Rose](https://github.com/GearsDatapacks))

- Fixed a bug where the JavaScript code generator could produce duplicate `let`
  declarations for internal variables after a `case` expression whose subject
  directly matches branch when existing variables with same exist in outer
  scope.
  ([Andrey Kozhev](https://github.com/ankddev))

- Fixed a bug where `gleam publish` wrote the wrong application name into the
  published package metadata for dependencies whose Hex package name differs
  from their internal OTP application name. This caused Mix-based projects to
  fail to build when they depended on Gleam packages with transitive
  dependencies.
  ([Logan Bresnahan](https://github.com/LoganBresnahan))

- Fixed a bug where cli would fail to complete https connections from behind a
  proxy with self-signed certificates. The cli now defaults to using system
  trust stores for trusted CAs, allowing use in proxied network environments.
  ([apsoras](https://github.com/apsoras))

- Fixed a bug where the language server's "add missing patterns" code action
  would not be offered when the cursor was on an inexhaustive `case` expression
  if another inexhaustive `case` appeared earlier in the same module.
  ([John Downey](https://github.com/jtdowney))
