A step-by-step tutorial to install Crystal and create, run, test, and build your first project using shards.
Getting started with Crystal is quick if you follow a few simple steps. In this guide, you’ll install Crystal, scaffold a new project, write a tiny program, run tests, and produce a release build.
I’ll keep it minimal and practical so you can get productive fast.
1) Install Crystal
brew install crystal
-
Linux
- Check the official installation page for distro-specific instructions:
https://crystal-lang.org/install/
- Check the official installation page for distro-specific instructions:
-
Verify
crystal --version
shards --version
Optional tools you’ll probably want soon:
- VS Code extension (Crystal + LSP): https://marketplace.visualstudio.com/items?itemName=crystal-lang-tools.crystal-lang
- Linter (Ameba): https://marketplace.visualstudio.com/items?itemName=veelenga.crystal-ameba
2) Create a new project
Crystal uses shards
(like Ruby’s Bundler) for dependency management and project scaffolding.
- App template (recommended for CLI apps and services):
mkdir hello_crystal && cd hello_crystal
shards init app hello_crystal
- Library template (if you’re building a shard/gem-like package):
mkdir my_lib && cd my_lib
shards init lib my_lib
This creates a basic structure (for an app):
hello_crystal/
├─ shard.yml
└─ src/
└─ hello_crystal.cr
3) Write your first program
Open src/hello_crystal.cr
and print a greeting:
# src/hello_crystal.cr
puts "Hello, Crystal!"
Run it:
crystal run src/hello_crystal.cr
4) Manage dependencies (when you need them)
If you add dependencies to shard.yml
, install them with:
shards install
You generally won’t need this for the very first “hello world,” but it’s essential once you pull in libraries like HTTP clients or web frameworks.
5) Format your code
Crystal ships a formatter:
crystal tool format
Run it from the project root to format all sources.
6) Add a simple test (spec)
Create a spec file:
# spec/hello_crystal_spec.cr
require "spec"
require "../src/hello_crystal"
describe "hello_crystal" do
it "runs without raising" do
expect { Crystal.main }.not_to raise_error
end
end
If your app doesn’t define Crystal.main
, you can test a function you write instead. For a beginner-friendly pattern, wrap your app code in a module:
# src/hello_crystal.cr
module HelloCrystal
def self.greet(name : String = "Crystal")
"Hello, #{name}!"
end
end
puts HelloCrystal.greet
And test it:
# spec/hello_crystal_spec.cr
require "spec"
require "../src/hello_crystal"
describe HelloCrystal do
it "greets with default name" do
HelloCrystal.greet.should eq "Hello, Crystal!"
end
it "greets a custom name" do
HelloCrystal.greet("World").should eq "Hello, World!"
end
end
Run tests:
crystal spec
# or verbose:
crystal spec -v
7) Build a binary
Two common ways to build:
crystal build --no-debug --release src/hello_crystal.cr -o bin/hello_crystal
- Using shards (works when
shard.yml
defines targets):
shards build --no-debug --release
Run your binary:
./bin/hello_crystal
For production-like builds (strict dependencies and no dev deps):
shards build --release --no-debug --production
crystal tool dependencies ./src/hello_crystal.cr
9) Optional: Lint with Ameba
Ameba is Crystal’s code style linter (similar to RuboCop).
brew tap crystal-ameba/ameba
brew install ameba
ameba
ameba --fix
Visual overview
Here’s a simple flow of your first project:
flowchart LR A[Install Crystal] --> B[shards init app hello_crystal] B --> C[Edit src/hello_crystal.cr] C --> D[crystal run] D --> E[crystal spec] E --> F[crystal tool format] F --> G[shards build --release] G --> H[Run ./bin/hello_crystal]
What’s next?
- Explore popular shards:
- Web frameworks: Kemal (Sinatra-like), Lucky and Amber (Rails-like)
- Linting: Ameba
- HTTP client: Crest
- Build a CLI tool, a web service, or a small library and publish it as a shard.
You’ve just created, tested, and built your first Crystal project. Keep it small, iterate quickly, and enjoy the speed and expressiveness of Crystal.
Source link