Skip to content
GitHub Repository Forum RSS-Newsfeed

Crystal 1.12.0 is released!

Johannes Müller

We are announcing a new Crystal release with several new features and bug fixes.

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


This release includes 142 changes since 1.11.2 by 14 contributors. We thank all the contributors for all the effort put into improving the language! ❤️


Below we list the most remarkable changes in the language, compiler and stdlib. For more details, visit the full changelog.


Respect alignments above alignof(Void*) inside union values. This is an ABI breaking change. Crystal makes no guarantees about ABI stability. Most users won’t be affected by this. (#14279)

Thanks @HertzDevil

Process termination handler

Process.on_terminate replaces Process.on_interrupt as a more potent and portable API for responding to termination requests (#13694). All current uses of on_interrupt can be replaced by on_terminate with the effect of responding to more termination triggers.

Method Unix Windows
on_terminate SIGINT, SIGHUP and SIGTERM Ctrl + C, Ctrl + Break, terminal close, windows logoff  and shutdown signals sent to a console application.
on_interrupt SIGINT Ctrl + C and Ctrl + Break signals sent to a console application

This removes the need for adding platform-specific handlers in your code base to handle terminations that were previously not covered by on_interrupt.

In addition, on_terminate also passes an instance of Process::ExitReason to the handler block, allowing it to react differently to specific termination events.

Process.on_terminate do |reason|
  case reason
  when .interrupted?
    puts "terminating gracefully"
  when .terminal_disconnected?
    puts "reloading configuration"
    puts "terminating forcefully"

puts "Waiting for termination"

Thanks @stakach


There are a couple minor improvements for concurrency which are foreshadowing more significant changes for the upcoming multi-threaded runtime enhancement.

  • Backtraces for unhandled exceptions in spawn are printed at once in multi-threading mode to avoid unreadable interleaving lines (#14220).
  • When opening a File, it’s now possible to disable blocking mode which is useful for pipes and character devices (#14255).
  • Some issues with atomics and locks got fixed and Atomic operations now receive an optional parameter to define the strength of ordering guarantees as Atomic::Ordering. New macro Atomic.fence adds explicit memory barriers (#14293).
  • Thread got a name property to identify the thread. It can be set at initialization or for the current thread with (#14257).
  • Init schedulers before we spawn fibers (#14339).
  • Use per-scheduler stack pools, helping recycling stacks (#14100).

Thanks @ysbaddaden

  • Add memory barrier to Mutex#unlock on aarch64 (#14272).

Thanks @jgaskins


We enabled support for OpenSSL 3.2 by fixing a bug in error handling for the OpenSSL 3.x series (#14219).

Thanks @ysbaddaden

Our own LLVM extension library libllvm_ext is no longer required when linking LLVM >= 18 (#14357) because all APIs are now directly exposed in libllvm directly. The Makefile automatically skips building libllvm_ext.o on LLVM 18 and above.

Thanks @HertzDevil


Thanks @HertzDevil

Operators with = suffix

Operators ending with = can now receive multiple parameters and blocks (#14159) and they are properly forwarded by the delegate macro (#14282). The operator #[]= can be called with with a block using method syntax: x.[]=() { } (#14161)

Thanks @HertzDevil

Windows progress

  • Handle invalid parameter error in MSVC calls to prevent an immediate process exit (#14313)
  • Install system dependencies in the Windows GUI installer (#14328)
  • Automatically detect MSVC tools on Windows interpreter (#14391)
  • Support @[Link]’s DLL search order in the interpreter on Windows (#14146)
  • Reserve stack space on non-main threads for crash recovery on Windows (#14187).
  • works across filesystems on Windows (#14320).

Thanks @HertzDevil



  • Add CRYSTAL_CONFIG_CC compiler config variable. This bakes in a reference to a specific compiler which is useful for 3rd party package managers such as Homebrew so that the compiler picks up the appropriate library paths (#14318).

    Thanks @straight-shoota

  • Support for NO_COLOR (#14260), --static on Windows (#14292), --single-module and --threads for eval and spec (#14341)

    Thanks @HertzDevil

  • Preliminary support for Solaris/illumos has landed in the compiler and stdlib.

    Thanks @HertzDevil

  • New CLI option --frame-pointers to control preservation of frame pointers (#13860)

    Thanks @refi64

  • short_reference for top-level macros was changed to ::foo instead of top-level foo (#14203)

    Thanks @femto

Compiler dependencies

The compiler’s own dependencies are now managed with shards (#14365). The source code in lib/ stays vendored in the repository, so shards is not required in order to build the compiler. It’s only used for updating the dependencies in a much easier way than than with the previous approach based on git subtree.

Thanks @straight-shoota

crystal tool flags

This release brings a new compiler tool: crystal tool flags (#14234). It prints all values passed to calls to macro flag? so you can extract all compile time flags that a program recognizes.

Thanks @straight-shoota

Formatter enhancements

Improved the formatter for ProcLiterals (#14209), asm with comments (#14278), white space in a.[b] syntax (#14346), calls without parentheses followed by doc comment (#14354), whitespace in foo () (#14439).

Thanks @HertzDevil, @straight-shoota

Shards 0.18.0

The bundled shards release was updated to 0.18.0.

This new shards release brings a couple of enhancements for Windows support, particularly support for more cache directories (#612), detection of symlink creation capability (#617) and a lot more improvements on internal tooling. Starting with this release, shards’ output by default is only colored if stdout is a TTY instead of always (#620).

Thanks @HertzDevil, @straight-shoota

Experimental: ReferenceStorage

Originally introduced in 1.11.0, the ReferenceStorage type was removed again in 1.11.1 due to compatibility issues with older versions of the standard library (#14207).

We now have an improved implementation that shows no compatibility issues. ReferenceStorage represents a static buffer for a reference allocation.

These APIs are still experimental and might be subject to change. We expect more features in this direction in future releases. Join the discussion about custom reference allocation at #13481.

Thanks @HertzDevil


  • Setter methods for timeouts with Number parameter (#14372).
  • Compile time flag openbsd6.2 got removed (#14233).
  • The spec runner’s state moved into Spec::CLI. This is only relevant for code which monkey-patches into the spec library (#14170).


We have been able to do all of this thanks to the continued support of 84codes 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!