The Crystal Programming Language Forum

Using Rust inside a Crystal program

It will be nice to write a Crystal program and when there is a need to squeeze more performance, to use call a Rust code from the Crystal program. In addition it will just be a fun way to learn both languages. Can someone share a step by step instructions for doing it?

Google search sent me to this forum but it didn’t give me concrete steps I can follow.


I believe it’s the same way you call C from Crystal.

Read this:
And this: (might be outdated, I don’t know where are the official Rust instructions for this)

Essentially, Rust can provide an API like C does. Then you link your object from file from Crystal and that’s it.

1 Like

I’m confused. How do you expect to gain more performance from Rust? Rust and Crystal should be roughly on par performance wise. Both compile to a LLVM backend, so even the optimizations are pretty similar. There are some differences in the runtimes, but I’m not aware that makes a big difference. Many benchmarks show Rust and Crystal performing pretty similar. Even if one had a slight edge over the other, it would most likely not justify the overhead for switching to the other.

This could still be a fun endevour, I just don’t think this makes sense when you’re looking for performance improvement.

1 Like

Rust has a more mature and performant multi-threading environment than Crystal currently has, which could be leveraged.

1 Like


Perfs are similar.
I use FFI to be able to use some crates in Crystal, it allows to use Rust’s echo-system.

If it helps, here’s a little POC in bulk.

├── Cargo.lock
├── Cargo.toml
├── Makefile
├── shard.yml
├── spec
│   ├──
│   └──
├── src
│   ├──
│   └──


ifeq ($(shell uname),Darwin)
    EXT := dylib
    EXT := so

all: target/debug/myrust.$(EXT)
	LIBRARY_PATH=$(PWD)/target/debug:$(LIBRARY_PATH) crystal build src/ -o myrust
	LD_LIBRARY_PATH=./target/debug ./myrust

target/debug/myrust.$(EXT): src/ Cargo.toml
	cargo build
	cd src

	rm -rf target myrust myrust.dwarf


name = "crystal-rust"
version = "0.1.0"

name = "myrust"
crate-type = ["dylib"]


name: myapp
version: 0.1.0

  - Nicolas Talle

    main: src/

crystal: 0.32.1

license: MIT

pub extern "C" fn string() -> *const u8 {
  "Hello World\0".as_bytes().as_ptr()

lib R
  fun string() : UInt8*

module Myapp
  VERSION = "0.1.0"

  msg =
  puts "from Rust #{msg}"

And to compile:


I use FFI (Rust) with the v0.34, but I have tested this POC only with Crystal v0.32.

To go further, callbacks help well. Pay attention to who has the ownership of the variables.


I love stuff like this because it’s like “mad scientist” type stuff :laughing: I can’t wait to see what else you come up with this.