---
title: Crystal 0.21.0 released!
version: 0.21.0
summary: Crystal has a new development release.
thumbnail: +
author: straight-shoota
---

[Crystal 0.21.0](https://github.com/crystal-lang/crystal/releases/tag/0.21.0) has been released!

As any release it includes numerous bugfixes, cool features and performance improvements - in [120 commits since 0.20.5](https://github.com/crystal-lang/crystal/compare/0.20.5...0.21.0).

# Exciting Changes

* **(breaking-change)** The compiler now reuses previous macro run compilations so `{% raw %}{{ run(...) }}{% endraw %}` is only re-run if the code changes
* **(breaking-change)** Spec now uses `it { ... }` instead of `assert { ... }`
* **(breaking-change)** `String` can now hold invalid UTF-8 byte sequences, and they produce a unicode replacement character when traversed. Also `\xHH` escape sequences are now supported.
* **(breaking-change)** `Zlib` was split into `Flate`, `Gzip` and `Zlib`
* `Slice` can be set to `read_only`, that's the default for `String#to_slice`
* added `HTTP::Multipart` and `HTTP::FormData`
* added lots of methods on `String` to strip and chop

# Other Breaking Changes
* **(breaking-change)** Renamed `Set#merge!` to `Set#concat`
* **(breaking-change)** `Crypto::MD5` is now `Digest::MD5`
* **(breaking-change)** `String#chop` is now `String#rchop`
* **(breaking-change)** `String#to_slice` now returns a read-only Slice
* **(breaking-change)** Removed `String#lchomp`. Use `String#lchop`
* **(breaking-change)** Octal escapes inside strings incorrectly produced a codepoint value instead of a byte value
* **(breaking-change)** Removed octal escape from char literals

Thanks to everyone who supported this release through contributions, reviews and suggestions.

* [CHANGELOG](https://github.com/crystal-lang/crystal/releases/tag/0.21.0)
* [API Docs](https://crystal-lang.org/api/0.21.0)
* [Milestone 0.21.0](https://github.com/crystal-lang/crystal/issues?q=milestone%3A0.21.0)
