Skip to content
GitHub Repository Forum RSS-Newsfeed

Crystal 1.4.0 is released!

Celebrating the first year of the 1.X series of our beloved language, we are delivering a new release with several bugfixes and improvements.

Below we list the most important or interesting changes, without mentioning the several bugfixes and smaller enhancements. For more details, visit the changelog. Those excited by the new interpreter might be happy to find the ongoing efforts to improve it.

Pre-built packages are available on GitHub Releases and our official distribution channels. See for installation instructions.

As usual, breaking changes are marked with ⚠️.


In this release we included 132 changes since the 1.3.2 release by 31 contributors. We thank all the effort put into improving the language! ❤️

Towards WASM support

Version 1.4.0 ships with, at the moment, minimal support for compiling into WebAssembly (linking the program with a WASI-based LibC). There are several important pieces missing; please check #10870 for details. The updated instructions to try it out are:

  1. Write a simple Crystal program, let’s say:
    puts "Hello WebAssembly!"

    and name it You can also try more complicated programs, but keep in mind that this is still experimental and not ready for production.

  2. You need to have wasm-ld installed on your system, it is the WebAssembly linker from LLVM. On some systems, it comes by installing lld. Confirm that it is installed by using wasm-ld --version. Please also check that its version is similar to Crystal’s LLVM version (crystal --version).

  3. You will need libc and libpcre compiled to the wasm32-wasi target. You can fetch a precompiled version of them here. Check for the wasm32-wasi-libs.tar.gz asset, download it and extract it.

  4. Cross-compile it with crystal build --cross-compile --target wasm32-wasi.

  5. Link it with
    wasm-ld main.wasm -o main-final.wasm  -L "$PWD/wasm32-wasi-libs" -lc -lpcre -lclang_rt.builtins-wasm32
  6. Run the WebAssembly module with wasmer main-final.wasm or wasmtime main-final.wasm and have fun.

Note: There is currently #11948 that will simplify steps 4 and 5 above.

Better type inference for instance and class variables

Previous to this release, a simple program like the following failed to type because it couldn’t infer the type of the instance variable:

class DisplayHello
  DELAY = 10.milliseconds

  @timer_countdown = DELAY

Now it compiles fine, inferring correctly that @timer_countdown has type Time::Span. It is also possible to omit types in other cases too (details):

class DisplayHello

  def initialize(delay : Time::Span)
    @timer_countdown = delay + 10.seconds



There are two relevant improvements in this class. First, there are raising variants of #find and #index, called #find! and #index! respectively:

[1, 2, 3].find! { |x| x > 1 } # => 2
[1, 2, 3].find! { |x| x > 4 } # raises Enumerable::NotFoundError

[1, 2, 3].index! { |x| x > 1 } # => 1
[1, 2, 3].index! { |x| x > 4 } # raises Enumerable::NotFoundError

Second, Enumerable#tally and #tally_by can be given an existing hash to populate.


Hash also got two improvements. First, select, select! and reject can now receive any enumerable. Prior to 1.4.0, only Array and Tuple were accepted.

Second, there is a new method Hash#update that, given a key and a block, updates the element with the resulting value of the block. The method returns the old value:

h = {"a" => 0, "b" => 1}
h.update("b") { |v| v + 41 } # => 1
h["b"]                       # => 42

Details in the docs.

Other remarkable changes

  • Support for LLVM 14 (#11905).
  • Completed compiler support for Int128 (#11576).
  • ⚠️ Support for scientific notation in BigFloat#to_s (#10632).
  • ⚠️ Drop support of undocumented flag skip_abstract_def_check (#9217).
  • New IO#getb_to_end method for reading all the Bytes of an IO (docs).
  • New macro method parse_type to parse a type given as a String (docs).

We have been able to do all of this thanks to the continued support of 84codes, Nikola Motor Company and every other sponsor. To maintain and increase the development pace, donations and sponsorships are essential. OpenCollective is available for that.

Reach out to if you’d like to become a direct sponsor or find other ways to support Crystal. We thank you in advance!