71 comments

[ 8.4 ms ] story [ 100 ms ] thread
For those that don't know: Crystal is like a typed Ruby with the performance and concurrency flow of Go.
> Crystal is like a typed Ruby with the performance and concurrency flow of Go.

I'm not up to date, but the scheduling engine was far behind Go in terms of parallelism. Crystal was always quite good at concurrency.

But Go is popular because it's so good at parallelism (and relatively safe with a garbage collector).

I know Crystal has been working on this for the last few releases, but I'd be surprised if it's matching Go on parallelism.

Go's runtime is quite the engineering feat.

It can often outperform hand-optimized Rust in worst-case parallel workloads (p99), despite Rust having a number of pretty huge advantages...

>It can often outperform hand-optimized Rust in worst-case parallel workloads (p99), despite Rust having a number of pretty huge advantages...

I will say this comes with the asterisk that it heavily depends on what your concurrent system/problems looks like!

...but more often than not when dealing with web problems and network IO, the shape of concurrency/parallelism I need looks exactly like Goroutines, and even as someone who uses Rust/tokio daily: the Go runtime is an incredibly engineered system that usually beats Rust in my experience for application dev tasks.

Anyways, I love Crystal's syntax around concurrency! I wish we lived in a world where it had tons of Google engineers optimizing the runtime :)

Goroutines are roughly 2kb in memory, and Crystal fibers are roughly 4KB, which is insane in any regard. I think Crystal is really interesting and worth considering, especially if you want something native that has OOP, I really would love to see Crystal used more in general.
Go is popular because Docker and Kubernetes made it popular, and it was designed by UNIX idols.

If only it had a few more features from 1970's languages, designed outside Bell Labs, or even those from Limbo that it still doesn't support.

Crystal core dev speaking.

In the previous release (1.21) we enabled Execution Contexts as a parallelism engine. https://crystal-lang.org/2026/07/12/releasing-execution-cont...

It's even more flexible than Go because you can tune different contexts for specific workloads. Go still has more advanced optimizations and overall better thread-safety in libraries. But we're working on that...

Thanks for the response!

My main critique - which I'm sure you're aware of - is that the hardest part of doing this is predicting what your workload is actually going to be like. That's what Go does so well. It can get almost anything right without you needing to hand-tune it.

While I have you - are y'all planning to implement FSMs and thunks (for recursion) at any time in the near future?

This is something Go is unlikely to ever do unless it becomes a Go2 language.

I don't know enough about your runtime to know if it's remotely feasible given the choices you've made.

That actually sounds awesome.

Mainly because normal Ruby is an awesome language to write code, and it is also a language that's tried and lost the spotlight because its performance is really, really low, even when compared only with other interpreted languages.

Ruby caught a second wind when they started putting effort into their JIT, which in our testing made it quite a bit faster than every interpreted language except JS in real world performance.

But then Python got a second wind in performance with better rewrite in Rust integration, but it looks like with the latest DHH keynote, Ruby might also go down that path.

My opinion is that I/O and concurrency ease of use and performance continues to be Ruby's weak point vs other interpreted languages. Which also happens to be Go's very few strong points.

...and a community the size of Elm.
I always describe Crystal as “Ruby and Go went off to Argentina and had a beautiful baby together. Who has grown up and has so much promise.”
what does this language excel at in particular? havent heard of it before and didnt find a clear use case / mission statement on the webpage. unless I'm missing where to find it. just curious to learn more.
Crystal is for when you want to write C with Ruby-ish syntax. It's been around for awhile, all the way back to when Ruby was required to get VC funding.

In my opinion, it doesn’t excel at anything beyond being pleasant to read. Maybe if Go hadn’t come along, it would have gained more traction and developed a better concurrency runtime. Very few companies are publicly using it.

Plus, since 00s Ruby = Ruby on Rails, so it didn't appeal to ruby (on rails) developers back then.

Is Crystal even relevant at all now?

It isn't interoperable with Ruby and I don't know of any reputable companies using Crystal.

It just looks like Ruby, but it isn't Ruby and it is a compiled language? OK?

I am not sure why I should learn this language?

Prior to LLMs, Crystal was my language of choice when I needed a distributable binary. It works great for this, and for the kind of packages I was writing - mostly agent-daemons lurking in servers - the networking worked great. The only real alternative was golang, which I've never really liked and has (had?) a more complicated linking story too. The typing worked well too, if used with discipline - if it compiled, I could be pretty confident it would work. I still have systems deployed running Crystal agents, in production, without issue or memory leaks, for years.

LLMs though - I confess they've changed the calculus. Now I no longer have to look at the language, and obey its stupid ideas about error handling, I just use golang for its better library support. But I still have a soft spot for Crystal!

What a ridiculously negative comment. Obviously ragebait, but I'll bite anyways.

Did you forget that until five minutes ago humans used to read the code? And they needed to understand it? Yes, there was an actual desire for great Ruby-like syntax without the implications of using it, like its performance characteristics and the need for an interpreter.

Yes, it didn't go mainstream. Should we all abandon every project we've ever worked on because they're not "relevant"?

There are Minecraft bots written in Crystal, which was the first time I'd heard of it.
Crystal never aimed at Ruby interoperability, it's inspired by Ruby's ergonomic syntax.

You should learn this language if you want the nice developer experience, great stdlib, managed memory, native performance. Similar reasons to why you'd learn Go.

> It just looks like Ruby, but it isn't Ruby and it is a compiled language?

It's close enough that porting things is often trivial (sometimes just slap a few signatures), as long as the code doesn't go crazy with metaprogramming. Yes, it's not the same and stdlib is a bit different. But it's a lot further than "looks like" Ruby.

Fast Ruby with no moat. Next.
Why would a programming language need or want a "moat"? The whole idea of a "moat" is a feature of certain kinds of business strategies. A programming language's task is to be useful, not somehow preempt or delay or undermine competition through its positioning.
I interpreted moat here to mean "killer feature". It seems the best pitch on this thread is "it's like Go but not" or "it's like Ruby but not".
An imitable killer feature isn't a moat, so the terms shouldn't be used interchangeably. And moats are often sort of broadly anti-social, or at best a necessary "cost" of letting the work get done. Network effects and platform advantages are that way, for example.

But I would think that as hackers, when we praise a programming language, we often have in mind virtues that are freely transportable to other programming languages; intrinsic achievements that can be learned from and applied broadly.

I want my programming languages to be lovely, concise, clear, expressive, powerful, fun, insightful, mind-bending, illustrative, flexible, convenient, well-integrated, cohesive, efficient, safe, or helpful. I don't want them to have moats. I don't want to have to say "I'm using this because I (or my industry) started using it years ago and it's sticky"; I want to say "I'm using this because it's good"!

Maybe a minor semantic dispute in the eyes of some, maybe a kind of excessive literalism on my part, maybe a futile resistance to to concept creep, old man yelling at cloud.

But ykwim?

I looked closely at Crystal when it first got popular but they removed the REPL which for me made Elixir a better choice.
They have an interactive mode right now (crystal i), but it's not very comprehensive. You cannot use certain libraries with it etc.

Shouldn't be terribly hard to make it good though. Some time ago, I added a JIT REPL in a few afternoons with Claude, ending up with roughly the same performance as their compiler, and with it working reliably with all the libraries I tested. But since they don't want LLM contributions in Crystal, I just left it as an interesting experiment and started working on my own language instead.

I've been doing precisely the same thing https://march-lang.org/docs/playground/
Crazy how easy it is these days, isn't it? The last 20% that matters is gonna be a bit harder though, I assume. Plus with everybody being able to do it means that making yours be interesting is going to be extra difficult.
It is a lot easier, but I've been working on this language project for almost 8 months now. I've spent a lot of time in research papers and thinking about both dev UX and how it works with LLMs. Knocking together a working compiler on LLVM is WAY easier now, but making something nice is still hard. A language is so much more than a compiler and syntax. So to your point, standing out is incredibly hard.

I'm doing this because it interests me and I'm learning, but it does feel quixotic at times.

Cool. I'm about 3-4 months in, this is the current result: https://hanki-lang.org -- sorry about the LLM smell. I haven't paid much attention to making the documentation beautiful yet.

Seems like you're slightly more ambitious with the features, I'm focusing more on a practical application language with ruby-like aesthetics.

That's a cool project! It's fascinating that we both landed on efect-y capabilities with a faile closed system `hanki run --deny io` in hanki and `forge cap inspect ./build/myapp --deny IO.Network`[1] for binary audits in March. In general though March requires a compiled program to declare it's needs and errors on undeclared IO, etc.[2]

This is super interesting, I really like it. Actor concurrency with effects is not as broadly implemented as it should be.

[1] https://march-lang.org/docs/capability-audit/#auditing-a-com...

[2] https://march-lang.org/docs/capabilities/#io-permission-caps

Is your source code online? I can't find it.

It’s sad that we don’t write code anymore, it takes a lot of the joy of stuff like this away.
Agreed. I saw the announcement and had an inkling of the excitement I got the first time I tried Crystal, years ago. I remembered how exciting new languages were to learn, and putz around with.

Then I remembered I could open [coding agent of choice] and it'd nearly oneshot whatever I would want to try in Crystal. I got a little disheartened.

Some languages for me were never meant to be 'used in production', but were a creative & learning space instead.

As someone who also feels that with new languages, I simply cannot relate to this idea that LLMs take that away somehow. To me, the limiting factor of all these langauges was (no shade to Crystal not really the case there these days) most of them have terrible or no docs, have terrible onboarding, have rough edges that may or may not be fixed.

So it was a gamble learning something new could just result in a brick wall dead end where you can't fix the thing, you can't get in touch with anyone who knows how (or has time), there's no docs to help you on the way, the code base is a mess and inscrutable, maybe written the a language you don't know -- maybe even the one you're trying to learn! It could be very frustrating at times, to the point I'd just pass over some interesting languages if they weren't polished enough. Which is a shame because I know there's good ideas in there, I just can't invest the time to make sense of them. Seems contradictory, but designers are not always the best communicators.

With LLMs, all this consternation is gone. Can it write the program for you? I guess... but also not really because for many niche languages with interesting features, the LLM won't do so idiomatically, opting instead to implement enough functionality to scaffold a Python-shaped solution, and then it writes that.

So the neat ideas are still there, the learning opportunity is still there, the ability to leverage technology in a way the LLM can't is still there. Especially in a creative and learning space!

People who work at the leopard breeding factory being upset that the leopards are being bred to eat their faces..
People love trotting out this phrase. But on analysis of its usage for the above comment, it doesn't make any sense. Who is the leopard, the breeder, and why are they upset in that above comment? They don't sound upset, just sad.
I think the leopard is software-as-automation, the breeder is the tech industry, and the exact semantics of "upset" are less important than schadenfreude at automation (and ensuing poverty) coming for the automator.
I think being sad is a form of being upset.
Not everyone gets to work at the factory, yet they still get their face eaten.
This reminds me of how, say, the YouTuber Practical Engineering works as an engineer, but then goes and builds physical models of how water moves under hydrostatic pressure out of perspex and sand in his garage for fun.
You can still write code. I do it every day, even for work.
I still do, thankfully not every customer is keen on letting vibe coded applications lose on their systems.
great that aarch64-linux support is now promoted to Tier 1! finally, I can convince my CTO to port some of our services in crystal for those cheap hetzner machines.
That's cool that you have Crystal in production! What are you using it for?
web services for some of our internal tools
Glad to see the continued progress on adding support for Windows.
Crystal might not be the most popular, but it is very interesting to me, I'm not a Ruby guy, but I was looking into other languages other than Go, Rust, etc that are natively compiled, I've dabbled with Nim, but I really wanted to try something slightly different, and I'm honestly impressed, it needs some slight polish still, maybe better funding might help, but in a different timeline under the right conditions, I genuinely think Crystal could have taken off as a really solid language. It's LLVM based, has green threads (that are insanely lightweight), has C-interop, has a comp-time macro system for AST inspection, code generation and removing boilerplate code.

The web frameworks look interesting too, but I haven't deep dived those just yet. You really get a Rubylike language with native performance which is very interesting.

One thing I wanted out of Nim is slightly more Python-likeness, I want regular OOP, since Crystal takes from Ruby (I believe it was originally written in Ruby, before it became self-hosting) it has sane OOP features I miss when I use Go, Rust or even Nim.

I really feel in a different timeline, Crystal could have been something, I also feel like "Ruby" for some leaves a bad taste, but Ruby is nowhere near as awful as most people think, even though it was never for me, it was still one of the nicest ecosystems I ever worked with long before Go got its package management situation situated.

Edit one more thought: I believe the Windows installer / Windows support for Crystal is a newer addition if I'm not mistaken, so it took a while before it got proper Windows support. Well, I just googled it, it started in 2023... but still, that's fairly recent by my book. I think any programming language should strive to work across the "big three" as soon as possible to increase adoption. Go took off the moment it came out for Windows and was formally released.

> I want regular OOP

Why would you want that? Just to continue the habit? I'd say regular OOP is, after implicit `null`, the biggest mistake in software.

Crystal is nice, but for network programming, Go simply cannot be beaten by a language that has a equally limited type system.

Opinions vary on OOP being a mistake. Most likely people with that opinion are responding to the influence of Java's popularity in the past. Or the confusion with how Javascript was prototype-based but with Java-like syntax and then it got classes for further sugar coating.

I don't think anyone who regularly uses Ruby or Python thinks OOP is a mistake, it's in how you use it and whether one likes the OOP design of the language.

I think that OOP, like Lisp, lost a lot when Smalltalk machines went out of vogue. Ruby is a super cool language but doesn't have the same breadth as a OOP-as-OS system.

I think the Lisps kind of have up on being an interpreter and I feel they lost some of their power because of it.

I kind of see Ruby waning right now, I don't think it offers much with the development of LLMs. I don't think adding typing is the key - but I anticipate there will be a kind of LLM-powered Smalltalk resurgence

You get "OOP-as-OS system" on Apple, Google and Windows platforms, to various levels of approximations.

With Objective-C/Swift, Java/Kotlin, .NET/C++/COM userspaces.

Lol fair point -

But you know what I mean, right? What would be a better way to describe it?

Halfway there I guess, the reason they aren't as you expressed, are the C and C++ layers that exist underneath them, not exposed to the debuggers and such.
Lots of people who use Python regularly, think its a mistake on this, and a lot of other levels. Lots of people use languages, because they feel enforced to do so, and not because of a concious choice.
Isn't Crystal significantly more expressive than Golang?
(comment deleted)
I get the hesitation from people used to C# or Java where OOP has always been the law of the land, but the rest of us who have used D, C++ or Python... to name a few... OOP is fully optional, and that's how I want OOP in any language, give me multi-paradigm any day of the week.

I would have loved Go more if they had made "lightweight" classes a thing, something feels wrong tying structs and functions, you could have added a wrapper around both to make the code more organized. I guess that's what I like about OOP, organized code. I don't even care about most OOP things, I just want to organize code in a meaningful way.

OOP is not optional in Python though, unless you are speaking about pre-2.0 Python, before everything became object instances, Smalltalk style.
You can have naked (top-level) functions in Python right? Are they also in instances of classes?
Functions are an object in Python too, I think that's why they're trying to get at. So you can do some funky things with them if you really want.

You certainly don't have to write OO Python if you don't want to. Objecting to functions being objects like the person you're replying to is, is a flavour of puritanism I find baffling.

They definitely are,

       Python 3.15.0 (tags/v3.15.0:d220409, Oct  9 2026, 11:55:56) [MSC v.1951 64 bit (AMD64)] on win32
       Enter "help" below or click "Help" above for more information.
       >>> def sum(x,y):
              return x + y

       >>> sum(40, 2)
       42

       >>> type(sum)
       <class 'function'>

       >>> dir(sum)
       ['__annotate__', '__annotations__', '__builtins__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__getstate__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__type_params__']
Kotlin has optional OOP on the JVM. I still use it, but sparingly. Barely ever classes inherit from other classes in my code; I use interfaces, mostly to be able to fake services for testing.

Most of what I write are functions and data objects (records, basically).

One pattern I use is classes with one function, where the constructor takes the functions dependencies, and the function only takes non-dependency parameters.

Functions and data objects are translated into OOP related JVM bytecodes.

Which is why, something like

    fun square(num: Int): Int = num * num
gets translated into

   public final class ExampleKt {
     public static final int square(int);
       0: iload_0
       1: iload_0
       2: imul
       3: ireturn
      }
    }

When running javap on the .class file.

People really should understand what they talk about avoiding OOP.

The biggest mistake on the design level seems to be pretty clearly the heap, as it complicates everything else by several orders of magnitude.
> I'd say regular OOP is, after implicit `null`, the biggest mistake in software.

I love this website. It proves that software "industry" is a pop culture after all.

I may be one of the few to use Crystal in anger for long running programs but unfortunately we had to do away with it because of longstanding issues in the runtime where exceptions at the wrong time during I/O bring the runtime to a halt. It's been a few years so I don't have the github issue off the top of my head anymore. It's a great language for CLIs though. I'm glad to see the team still pressing on.
I used Crystal for a year before moving on to Go, which I value for its faster build times. Bun also keeps improving at fast pace and constantly reduce memory usage which can be useful on budget server.
I've been happy using Crystal for many things. It's very convenient for small server deploys. When processing a lot of execution traces I ported previous Ruby code to get 40x support boost and 3x memory reduction, while keeping the code virtually the same.

And it's nice to see each version is getting better. The reference could get some love, but it's still ok.

One of the biggest complain about Crystal is its compile time. Unfortunately there isn't an easy fix.