DEV Community

Cover image for Doing Crystal #2: Getting started with Crystal
Chris Watson
Chris Watson

Posted on • Originally published at Medium

Doing Crystal #2: Getting started with Crystal

Hello and welcome to another edition of Doing Crystal. In this article I’m going do a brief overview of the installation of Crystal, Crystal Shards, using the CLI, and setting up a new project.

If you haven’t yet read the first part of this series you can check it out here.

Crystal is pretty easy to install, but sometimes there are hangups. As the language has matured (remember, it is only a 5 year old language) the installation process has gotten simpler and more OS’s are now supported than before. That being said, here are some things to keep in mind:

Windows Support

This is probably the biggest hangup for a lot of people just getting started with Crystal. As of the writing of this article, Windows is not supported by Crystal. There are ongoing efforts to port the compiler and make compiling on Windows possible, but for now you have 2 options if you want to get started with Crystal on Windows.

  1. Install Linux. You can dual boot, use a VM, or just get rid of Windows all together, but Linux is definitely the best way to develop with Crystal.
  2. Use WSL. This is still using Linux technically, but a little easier. WSL (or the Windows Subsystem for Linux) is a native kernel compatibility layer that allows you to run real Linux inside of Windows. The one hangup here is editor support, which I tried to mitigate with my project wsl-proxy. Support for WSL has also been added to the Crystal Language plugin for VS Code.

Compiling from Source

Compiling from the source files can be quite difficult if you don’t know what you’re doing. There are several libraries that are required before you can build the compiler. On systems for which there are instructions, namely Ubuntu, Fedora, and OS X, it’s pretty easy to download and install the libraries you need, but for systems such as Arch or Alpine Linux finding the correct libraries can be a little more difficult.

Luckily help is literally a click away.

General installation instructions are located at


Ruby has Bundler, NodeJS has NPM, Rust has Cargo, and Crystal has Shards. Shards is a package manager and, like Crystal itself, is still in its infancy. That being said Shards is good at what it does: fetching and installing external Crystal libraries from a git repository.

Shards should come pre-packaged with Crystal. To check if you have it installed, run shards --help.

If you have shards installed and it is correctly referenced on your PATH you should see this output. The available commands are as follows:

  • build — the build command checks your shard.yml for binary definitions and builds them if any exist. You can use the [targets] option to build specific targets.
  • check— checks that your dependencies are up to date.
  • init — generates a shard.yml file in the current directory.
  • install — installs dependencies listed in your shard.yml.
  • list — lists installed shards.
  • prune — removes installed shards that are no longer needed.
  • update — updates shards.
  • version — gets the version of a project.

Unfortunately, installing binary shards (like you can with gem install [gemname] in Ruby) is not yet supported, but hopefully someday it will be.

The Crystal CLI

The Crystal CLI is an interface to the compiler, the Crystal Playground, tools, documentation generation, test running, and more. First run crystal --help to see if you have it installed correctly.

If you see this then you’re good to go. Let’s review the CLI’s commands.

  • init— Generates a new Crystal project. You can use crystal init lib [name] to generate a library project, or crystal init app [name] to generate a binary project.
  • build — builds a file. In most cases you’ll run crystal build ./src/, where is the main file that was generated for you when you ran crystal init.
  • docs — Crystal comes with a built in documentation generator. Personally I feel like there’s a lot missing where documentation generation is concerned, but you can pretty easily generate docs using your comments and type definitions just by running crystal docs.
  • env — prints the environment information for Crystal. ENV vars include CRYSTAL_CACHE_DIR, CRYSTAL_PATH, CRYSTAL_VERSION, and CRYSTAL_LIBRARY_PATH.
  • eval — evaluates and runs Crystal code from the standard input.
  • play — starts a local Crystal Playground server. This is somewhat like the playground located at
  • run — builds and runs the supplied filename. Use like crystal run [file].
  • spec — builds and runs specs located in the /spec directory.
  • tool — runs one of the available Crystal tools. Available tools are context, expand, format, hierarchy, implementations, and types.

Now that we’ve gone over the CLI a little, let’s set up a new project.

Creating a Project

Because it’s been deemed mandatory by the coding gods, let’s create a hello world application.

First let’s open up our terminal of choice and cd into a projects directory. In my case I’ll run cd ~/Projects. Using the CLI, we’re going to generate a new project scaffold, and then cd into our newly created project.

If you run ls you should see the following output:

The important files here are shard.yml and src/ First let’s take a look at shard.yml.

I won’t go over this in detail, as most items should be self explanitory. If you need help with the available options in shard.yml you can look at the spec here.

Let’s open our main file located at src/

This is the boilerplate content generated for all new Crystal projects. As you can see our project name of hello_world has been PascalCased for the name of the base module. As a convention Crystal uses snake_case for project names, method names, variable names, etc. and PascalCase for constants such as module names and class names.

Now, as convention dictates our hello world application must print something like “Hello, World!” to the console, so let’s make it happen.

For the sake of this example we’ll be a little more verbose than we have to.

First we create a new class method in the HelloWorld module called say_hello. You can differentiate class and instance methods by looking for the self. syntax. def self.say_hello makes a class method, where def say_hello makes an instance method.

Our say_hello method takes one argument “name” which is assigned a default value of “World”. If we were to run say_hello without any arguments the default value of “World” would be used.

Next we go outside of the HelloWorld module to run our new method. As say_hello is an instance method we can call it with HelloWorld.say_hello. Class methods can not be used directly on modules as modules cannot be instantiated.

We finish things off by calling HelloWorld.say_hello("Manas") to give a shoutout to the people at Manas Tech who created Crystal.

Let’s run our program and see the output.

The program will take a few seconds to run as it has to compile first, but you should be greeted with a “Hello, Manas!”. Congratulations! You have written your first Crystal program. Replace run with build to build a binary to your current directory.


Crystal is an extremely powerful language and we’ve only scratched the surface so far. Next time we’ll discuss one of the many things that makes Crystal so powerful, it’s type system.

Please don’t forget to hit the Ego Booster button that looks like someone clapping, and if you feel so inclined share this to social media. If you share to twitter be sure to tag me at @_watzon.

Some helpful links:

Find me online:

Top comments (4)

megatux profile image
Cristian Molina

I use asdf version manager to install Crystal and other languages & DBs

watzon profile image
Chris Watson

I actually didn't know about that before. I may have to install it.

megatux profile image
Cristian Molina

Nice, thx. I think ruby "gem install" for binary libs does compile code, not install binaries.

watzon profile image
Chris Watson

Well Ruby doesn't compile. If the gem has linked C++ it will compile the linked libraries, but Ruby itself doesn't compile. Typically gem install will download the gem from the repository and, if there are any files in the gems bin directory that are referenced in the gemfile it will link them to /usr/local/bin or something. Typically those files are just ruby files made to run as shell scripts.