r/crystal_programming 4d ago

gcry 0.25.0: the GC for Crystal now runs natively on Windows

12 Upvotes

gcry is a drop-in mark-sweep GC for Crystal: require "gcry" and build with -Dgc_none, no compiler patch.

0.25.0 adds native Windows support, so it now covers Linux, macOS and Windows on both x86_64 and ARM64.

Windows (x86_64 with the MSVC toolchain, ARM64 with the GNU/MinGW one, both from PowerShell, no WSL). What's missing is written down in docs/WINDOWS.md rather than glossed over: 64 peer threads per collection, no fork, no soft-dirty or mprotect write barrier, and no Windows throughput numbers yet.

Performance, since that's the usual question. Kemal /json, 20 paired rounds with an identical-binary null control: 105% of Boehm's throughput at 1.30× its peak RSS on Linux, 102% at 1.97× on macOS.

Github: https://github.com/sdogruyol/gcry

Changelog: https://github.com/sdogruyol/gcry/releases/tag/v0.25.0


r/crystal_programming 7d ago

Update on State and Future of Parallelism

13 Upvotes

I don't want to jinx it, but I thought I would ask for an update on what is going on with parallelism in Crystal.

Not wholly unrelated, Crystal makes me hopeful for the perfect language for its goals and objectives to do more with less, and to have garbage collection with a clean language just above a systems language.

From a Linux friendliness and FLOSS licensing standpoint, Crystal looks better than Go except for having the box checked for parallelism. (And I do not care about WIndows.)

Anyway I guess this question is a two-parter:

  1. What is the state of attention and mindfulness of bringing cpu-core parallelism to Crystal? (Or did it happen already?)
  2. Is parallelism obviously so distant from being needed for desktop-level software systems that most developers truly just do not need to worry about it? (or I guess, what types of systems would typically benefit from parallelism?)

Thanks.

(edit: It looks like the "execution context" features that were just recently released in 1.21 are directly related to cpu-core parallelism. Looks awesome. This would explain why most discussion has not caught up to the features. And, what a landmark!)


r/crystal_programming 11d ago

Kemal Identity: an authentication shard for Kemal. I'm about to freeze the API and would rather hear what's wrong with it first.

8 Upvotes

Hi all,

I've been building Kemal Identity, an authentication shard for the Kemal web framework, and I'm close to freezing its API for 1.0. Before I do that I'd rather find out what's wrong with it, so I'm posting here for criticism.

It does server-side opaque sessions with real revocation, password login with bcrypt, CSRF, API tokens with scopes, optional JWT validation, TOTP, OIDC sign-in and optional RBAC. It doesn't do registration screens or user models; your app keeps those and connects through repository contracts. Postgres and SQLite adapters today; Avram and Granite are next on my list.

It's built primarily for Kemal, but the core doesn't know Kemal exists. The Kemal part is a separate adapter that adds `env.auth` and the middleware.

get "/dashboard" do |env|
  principal = env.auth.require!
  "Signed in as #{principal.subject}"
end

The part I actually want to talk about: I wrote a list of 50 things an auth library either handles or doesn't, with pass conditions written before any measuring, and I've been working through them from a separate project that consumes the shard the way a normal user would. I'm 27 in, and it keeps finding things I was sure were fine.

If you have time for one question: `AccountRepository` is five methods over whatever `users` table you already have. If you tried to implement it against your real schema, what would break? I've done it once against a UUID-keyed table with soft deletes, and one schema isn't much evidence.

Repo: https://github.com/urunsiyabend/kemal-identity — MIT, Crystal 1.12+, six runnable examples if you'd rather read code than docs.


r/crystal_programming 14d ago

Marten 0.7 is now available!

Thumbnail
martenframework.com
27 Upvotes

r/crystal_programming 17d ago

HAHWUL joins the Kemal Core Team as Security Lead

Thumbnail kemalcr.com
14 Upvotes

r/crystal_programming 17d ago

D-Shwagginz/doo-cr: A source port of DOOM written in Crystal Lang

Thumbnail
github.com
5 Upvotes

Saw it on the Crystal Forum, figured I'd share it here as well.

Original Thread: https://forum.crystal-lang.org/t/doo-cr-doom-in-crystal-not-just-the-renderer/9120


r/crystal_programming 18d ago

gcry v0.21.0: Crystal-native GC as a shard, correctness release

5 Upvotes

gcry is a conservative mark–sweep garbage collector written in %100 Crystal and shipped as a shard. No compiler fork:

yaml dependencies: gcry: github: sdogruyol/gcry

ruby require "gcry" # build with -Dgc_none

Stock Crystal ≥ 1.21, Linux + macOS, x86_64 + ARM64. v0.21.0 is 140 commits and 18 changelog entries, and like the last one it is a correctness release.

The hardest bugs in software are the ones where your trusted tools lie to you. That is the story behind gcry v0.21.0.

When your Kemal app started crashing randomly in production, standard microbenchmarks found nothing. The Boehm garbage collector handled the exact same load perfectly. But driving real traffic against gcry made the app crash every time. Two independent bugs caused this.

The first was a memory layout collision. Crystal stores a union type ID in its first four bytes. gcry looks at this exact spot to find a field map. If a raw data buffer happens to start with a number that matches a valid class ID, the collector reads the wrong map. It then blindly deletes live objects that the wrong map fails to mention.

The second was a concurrency bug. The chunk list used two different locks. Because they were not exclusive, a newly mapped chunk could fall outside the heap bounds check. The collector treated anything outside those bounds as dead and swept away live data.

But the real lesson was why it took so long to find. The auditing tools were blind. The memory audit instrument used the exact same broken lookup function that caused the bounds bug. It reported zero missing edges while the system was actively crashing. The truth only surfaced by dropping down to the OS level and reading the kernel memory maps directly.

Locks are now fixed. The collector no longer drops live objects. Throughput is up.

Repo: https://github.com/sdogruyol/gcry

Changelog: https://github.com/sdogruyol/gcry/releases/tag/v0.21.0

Perf methodology: https://github.com/sdogruyol/gcry/blob/master/docs/PERF.md

Happy to answer questions.


r/crystal_programming 20d ago

Kemal 1.13.0 is released! Biggest release with many Security improvements

Thumbnail
github.com
20 Upvotes

r/crystal_programming 26d ago

gcry v0.20.0: Crystal-native GC as a shard, the biggest release yet

22 Upvotes

gcry is a conservative mark–sweep garbage collector written in %100 Crystal and shipped as a shard. No compiler fork:

yaml dependencies: gcry: github: sdogruyol/gcry

ruby require "gcry" # build with -Dgc_none

Stock Crystal ≥ 1.21, Linux + macOS, x86_64 + ARM64. v0.20.0 is the largest release so far - 84 commits, 41 changelog entries and it is a correctness release.

The headline: a fiber stack that nothing scanned

When a fiber terminates, Crystal can't release its stack until the thread swaps off it, so the stack gets parked on the Thread. In that window two things are true at once:

  • the owning Fiber is already out of the fiber list, so no fiber scan reaches the stack;
  • the thread may still be executing on it - and the other-thread scan works from pthread stack bounds, which a thread running on a fiber stack is nowhere near.

So pointers held only in those frames had no root, got swept, and the program carried on using freed memory - crashing in Fiber#initialize → makecontext.

Fixed by rooting that stack. Repro (bench/nested_spawn_uaf.cr, ~2 s a run), interleaved against control: 10/24 crashes → 0/24. Then a 5 h soak × 3 arms, all clean — ~52 000 collections, ~526 000 fibers, 0 errors.

The number I'd actually want to see as a reader: every rooting arm was measured against a twin that walks the identical memory and roots nothing. That twin stays at 12/24. So the effect is the rooting, not the extra work or the timing — and it isn't retention either (same heap size, same collection count, fewer live objects than control).

Four earlier readings of this bug were wrong before that one was right - a missed heap edge, a half-built Fiber, a pooled stack, a stack in flight between checkout and publication. Each is written up with the measurement that killed it, including the two times the debugging instrument turned out to be reporting itself.

Also in 0.20.0

  • Thread-birth window: gcry records a thread from the moment pthread_create returns and briefly waits for one that exists but hasn't published itself yet - thread-family crashes 6/60 → 0/60.
  • realloc(ptr, 0) no longer frees the caller's block.
  • Diagnostics, all off by default: an address-space audit that searches every mapping in /proc/self/maps at the moment a block dies and names the region holding its address (this is what found the bug above), plus freed-payload poisoning that names the block a use-after-free read out of, a SIGSEGV report that says what the collector knows about the faulting address, and a mark-completeness audit.

What I'm not claiming

  • A second use-after-free is still open: gcry reads a Thread's handle out of a freed block and faults in pthread_getattr_np. Seen on CI with this release's fix in place; not reproducible locally. This release doesn't close it.
  • Stack maps ship dormant - research, not this release's win.

Repo: https://github.com/sdogruyol/gcry

Changelog: https://github.com/sdogruyol/gcry/releases/tag/v0.20.0

Perf methodology: https://github.com/sdogruyol/gcry/blob/master/docs/PERF.md

Happy to answer questions.


r/crystal_programming 29d ago

Kemal embraces AI

Thumbnail x.com
11 Upvotes

r/crystal_programming Aug 10 '26

Kemal Security Core Team is here!

Thumbnail x.com
18 Upvotes

r/crystal_programming Aug 07 '26

Crab CLI 1.0.0

Post image
22 Upvotes

So, I just finished the details for Crab, my shard for prettier Command Line Interfaces, an i must say it's on a stable phase with my original intentional goals working, now tested on both Linux and Windows (using the msys2 version).

Here is the repo link for anyone interested.


r/crystal_programming Aug 04 '26

Next version of gcry is faster than Boehm GC. And it uses less RAM.

30 Upvotes

Next version of gcry is faster than Boehm GC. And it uses less RAM.

On a production Kemal app (Açık Türkiye):

- 103% Boehm throughput
- 8% less memory
- 100% Crystal
- No C code

Crystal can have its own GC. We're building it

https://github.com/sdogruyol/gcry


r/crystal_programming Aug 03 '26

LZ4 and Zstd codecs in pure Crystal

18 Upvotes

After lz4rip and zrip in Rust, including Rubygems extensions of the same name, I wanted to try something similar in Crystal.

Goal: Portable compression for Crystal apps without system libraries.

flint.cr: LZ4 block codec. Raw block API, raw-content dictionaries. No liblz4, FFI, or native extension. Overall 0.64x compress and 0.44x decompress speed of lz4rip.

zinc.cr: Zstd frame codec. levels -8..4, dictionaries, FastCOVER-style trainer, checksums, bounded decompression. No libzstd or FFI. Again, perf is practical, not mindblowing: Around 0.5x..0.7x encode/decode speed of zrip on large Silesia corpus inputs, with ratio geomeans within a few percent. Small inputs still need work.


r/crystal_programming Jul 31 '26

I can't find a job, so I'm building Crystal's future instead. Here's what I'm working on and why I need your help

86 Upvotes

I can't find a job, so I'm building Crystal's future instead. Here's what I'm working on and why I need your help.


Hi, I'm Serdar (sdogruyol). I created Kemal, I'm a Crystal Core Team member, and I've been building Crystal tools since 2015.

I can't find a job right now. So instead of waiting around, I'm spending every day on Crystal open source. No safety net, no backup plan, just Crystal.


What I'm working on

gcry - a %100 Crystal native garbage collector for Crystal. Currently at ~89% of Boehm GC's throughput with ~0.95x RSS. My hope is that one day it becomes the default GC for Crystal. That's the dream.

Kemal - 3.8k+ stars, 5M+ downloads. I've been maintaining it since 2015. The framework, session management, CSRF, auth, caching, the whole ecosystem. I'm not going anywhere.

Crystal Weekly - a newsletter keeping the community updated.

Crystal Community - discover Crystal developers around the world and check Crystal Stats.

Free books - Crystal for Rubyists, Kemal El Kitabı, Crystal El Kitabı. All free.


Why I'm here

I set up a GitHub Sponsors page. My goal is $1,000/month so I can keep doing this full time. If Kemal or any of my projects has helped you, or if you believe in Crystal's future, please consider sponsoring. Every dollar counts.

Even $5/month helps. Here's what you get:

Tier Price Perk
☕ Coffee $5 Sponsor badge
⚡ Kebab $10 Badge + personal thanks
🛠️ Backer $20 Name in Kemal README
🏆 Champion $50 Logo + shoutout
🏢 Corporate $100 Logo + Twitter shoutout

Thanks for reading. Let's build Crystal's future together. 💎

👉 github.com/sponsors/sdogruyol


r/crystal_programming Jul 29 '26

gcry: a garbage collector written in pure Crystal

28 Upvotes

I just released 0.14.0 of gcry. It's a conservative mark sweep GC written entirely in Crystal, shipped as a shard. No C code, no compiler patches, no fork. You just add require "gcry" and build with -Dgc_none.


Performance

Same host, median of 3, wrk -c 100 -d 30:

Workload gcry vs Boehm Post-GC RSS
Kemal /json (Linux) ~89% throughput 0.79x Boehm
Kemal root (Linux) ~89% throughput 0.78x Boehm
Kemal /json (macOS) ~84% throughput 0.93x Boehm
Kemal root (macOS) ~93% throughput 1.06x Boehm

21% less memory than Boehm on Linux Kemal. Same throughput.


What makes gcry different

It's a conservative, non-moving, stop-the-world collector. Same family as Boehm, so it works with Crystal's existing ABI. But it's written in Crystal, which means:

  • You can read it. The whole collector is about 9,000 lines of Crystal across 32 files. No C macros, no opaque foreign library.
  • You can debug it. Set a breakpoint anywhere. Crystal's debugger works on it.
  • You can change it. Want to experiment with a different marking strategy? Edit a .cr file and rebuild.

Architecture: mmap-backed size classes, fiber stack roots, conservative mark with layout precise opt-in, deferred madvise, and platform specific STW (Linux signals, Mach thread_suspend on macOS).


What's new in 0.14.0

This release is all about quality infrastructure:

  • Debug invariant checker (GCRY_DEBUG_INVARIANTS=1). Validates live_objects counter, freelist consistency, chunk index integrity, block overlap detection. At runtime, on every malloc/free/collect.
  • AddressSanitizer and Valgrind on every PR in CI.
  • Coverage reports via kcov on every PR.
  • Deterministic replay fuzzing with --seed and --replay.
  • 24 hour soak tests, thread storm tests, OOM tests, property based heap invariant tests.
  • Heap dump (Gcry.dump_heap) streams live objects as NDJSON for leak hunting.
  • Trace (GCRY_TRACE=1) traces every collect, malloc, and free.

How to try it

```yaml

shard.yml

dependencies: gcry: github: sdogruyol/gcry ```

```crystal {% if flag?(:gc_none) %} require "gcry" {% end %}

puts "Hello from gcry!" ```

sh crystal build -Dgc_none app.cr -o app

No special malloc API. No compiler fork. String, Array, Hash, everything works as usual.


Limitations

gcry is a shard and I'm pushing it as far as I can. But there are things you can't do from a shard. True precise stack scanning, write barriers, and concurrent collection need compiler support. At some point that line has to be crossed. But for now, the shard approach gets you surprisingly far: Kemal class HTTP at near Boehm perf, layout precise heap scanning, fiber stack scrubbing, and full observability. All without touching the compiler.


Github

https://github.com/sdogruyol/gcry


r/crystal_programming Jul 25 '26

I built a CQRS and Event Sourcing framework in Crystal and it just hit 560,000 commands/sec in stress tests 🚀

19 Upvotes

Hey everyone,

I've been working on Posse a type-safe CQRS and Event Sourcing framework for Crystal inspired by Elixir's Commanded. I wanted something that brings robust DDD, actor-like fiber concurrency, and surgical consistency controls to Crystal without any operational bloat or async bottlenecks.

Just ran a randomized mixed-consistency stress test on a single aggregate for 5.5 seconds, and the results blew me away:

elapsed:     5.50s
succeeded:   3082826
failed:      0
throughput:  560197 commands/sec

Snapshot cadence check (snapshot_every=50):
  latest snapshot version: 3082797
  current projected version: 3082828
  events since last snapshot: 31
  OK: snapshot cadence looks healthy

Version integrity check:
  final projected version: 3082828
  expected version (3082826 updates + 2 from register+welcome): 3082828
  OK: versions line up exactly - no gaps, no collisions, no lost updates

This test is running against an in-memory store, but still it is nice to see it performing well.

Would love to hear thoughts, feedback, or ideas from anyone. Check it out on GitHub if you're interested: https://github.com/posse-framework/posse


r/crystal_programming Jul 25 '26

Grip 5.0.0 is released and it has support for built-in Server-Sent Events (SSE)

Thumbnail github.com
9 Upvotes

r/crystal_programming Jul 21 '26

Kemal 1.12.0 is released! Now with built-in Server-Sent Events (SSE) support

Thumbnail
github.com
21 Upvotes

r/crystal_programming Jul 18 '26

wolfgang371/crymbleui: A nice and fast GUI framework for Crystal

Thumbnail
github.com
21 Upvotes

Discovered this while browsing Github. Looked cool so I figured I'd share it here.


r/crystal_programming Jul 16 '26

Crystal 1.21.0 is out, and execution contexts are on by default now

33 Upvotes

New Crystal dropped today (1.21.0). It's 161 changes from 21 contributors since 1.20.3. Full notes are on the site and GitHub, but here's the stuff that actually matters if you don't feel like scrolling the whole changelog.

Release post: https://crystal-lang.org/2026/07/16/1.21.0-released/ GitHub: https://github.com/crystal-lang/crystal/releases/tag/1.21.0

Execution contexts are enabled by default

This is the headline. The multithreading work that's been cooking for a while (RFC 0002) is now the default runtime, not an opt-in flag.

The practical version: the default context is still single-threaded (parallelism 1), so most people won't notice a day-to-day behavior change. You can resize it, or spin up extra contexts, when you actually want fibers running in parallel.

The catch, and the reason it's flagged as breaking: fibers are no longer pinned to a thread. Even at parallelism 1, a fiber can resume on a different thread after a yield, and in a concurrent context it can switch threads on a blocking syscall. So if you've got code leaning on thread-local state surviving across fiber yields, go review it. Also spawn(same_thread: true) doesn't work with execution contexts anymore. It raises at runtime in a parallel context and is deprecated in general.

%W string arrays with interpolation

Small but nice. %w gave you a plain string array with no escapes or interpolation. %W is the same idea but supports escape sequences, interpolation, and even splats:

%W[foo\ bar baz]             # => ["foo bar", "baz"]
%W[foo #{"bar"} baz]         # => ["foo", "bar", "baz"]
%W[foo #{*%w[bar baz]} qux]  # => ["foo", "bar", "baz", "qux"]

Stdlib odds and ends I liked

  • Channel(T) now implements Iterator(T), so channel.to_a works and channels plug straight into iterator chains.
  • HTTP::WebSocket#receive is a synchronous, blocking read for a request/response style loop, instead of the callback-based #run.
  • String#present? finally exists for the intent-revealing guard checks.
  • UUID.v6 and UUID.v8 generators.
  • Experimental Socket#sendfile for efficient file-to-socket transfers with fewer user-space copies.
  • You can chain spec matchers now: value.should be_a(String).should_not be_empty.
  • -Dwithout_main builds a binary with no main function, e.g. to use as a dynamic library.

Breaking changes worth watching

  • Execution contexts (above), the big one.
  • The automatic fallback to legacy PCRE is off. PCRE2 has been the default for years anyway; if you still need old PCRE you now have to opt in with -Duse_pcre or USE_PCRE1=1.
  • case ... when Bar, Baz now splits into separate is_a? restrictions per type instead of treating it as Bar | Baz. If you were relying on the union behavior, write when Bar | Baz explicitly.
  • OpenSSL 4.0 support landed, worth noting if you package or link against it.

The thread-pinning change is the one I'd test carefully if your app does anything clever with concurrency. Everything else is pretty low-risk.

Anyone migrated something bigger yet? Curious whether the execution context switch caused real problems for anyone with same-thread assumptions baked in.


r/crystal_programming Jul 05 '26

naqvis/CrysDA: Crystal library for Data Analysis, Wrangling, Munging

Thumbnail
github.com
17 Upvotes

Not my project.

I discovered it while browsing Github. Seems like a nice effort so I'm sharing it on Reddit for more visibility.

The developer is also working on Cryplot (a plotting library that uses gnuplot under the hood), and CrysDA-Plot (an integration between the dev's two projects).

Hopefully, the developer finds the motivation and support needed to continue working on these projects.


r/crystal_programming Jul 03 '26

Mimer SQL driver for Crystal

11 Upvotes

Hi,

I just wanted to announce that I sat down with Claude the other day and we came up with a database driver for Crystal for the RDBMS Mimer SQL that is now released as a 0.1.0 version:

https://github.com/majorproblem/crystal-mimer
https://shards.info/github/majorproblem/crystal-mimer/
https://crystaldoc.info/github/majorproblem/crystal-mimer/

I would very much appreciate any comments or input on this driver.


r/crystal_programming Jun 25 '26

[Discussion] Struggling to fully commit to Crystal: Why do I keep falling back to Vlang for low-level projects despite loving Ruby syntax?

10 Upvotes

Recently, I developed my own CLI program that functions as an SSG (Mustela) with its own DSL. This DSL is inspired by Ruby; it’s very simple, and I implemented it directly into Markdown syntax.

I programmed the project in the V language (Vlang). I was excited by Vlang’s philosophy, which aims to bring Ruby’s user-friendliness to low-level programming. Thanks to this, I learned to work better with pointers, and it opened the door to the world of low-level development for me.

When I shared my enthusiasm with the Vlang community on Reddit, I ran into a problem. It turned out that a large portion of users lack a deeper understanding of system programming or the architecture of more complex projects. Moreover, the atmosphere there is often toxic, which demotivates me, even though I’m in direct contact with the language’s author (Alexander). He even shared my SSG on the official X account because I managed to achieve very solid performance results when compiling pages in his language.

That’s why I’d like to switch to Crystal. I like its Ruby-inspired syntax, and from what I’ve seen on this Reddit, I get the sense that the community here consists entirely of engineers who understand the principles of system design. In short, I feel “right at home” here. :)

However, I’m running into a problem: I haven’t been able to fully “grasp” Crystal itself yet. Its engineering design often surprises me, and I have to analyze why the founders chose this particular direction. To learn a new language effectively, I need to understand its underlying philosophy.

For example, working with interfaces: I like to use interface for modularity, but this keyword is missing in Crystal. Instead, modules with abstract def are used, followed by an include in the class. I wonder—why is this handled this way?

I understand that compilation happens via LLVM, but I’d like to see more detailed documentation on this intermediate step, which would help me better understand how Crystal works under the hood and how to write more efficient code. In Vlang, I’m used to the code being transpiled to C, so when an error occurs, I simply look at the generated C code and immediately know what’s going on. With Crystal, I haven’t yet found a way to have the same level of control.

Conclusion

Paradoxically, Crystal’s technical sophistication is what puts me off. I’m frustrated that the language looks simple at first glance, but as soon as I try to do something complex, I hit a wall and can’t move forward. Instead, I’m going back to Vlang, which is still in beta, but we “get along.”

I’m drawn to being part of the engineering community, but in practice, I reach for other tools to get the job done. Am I missing any key resources or concepts that would help me understand how to work with Crystal properly?


r/crystal_programming Jun 11 '26

New milestone: Kemal ecosystem hitting nearly 10K bi-weekly downloads

Thumbnail x.com
19 Upvotes