micro-crystal
µCrystal
A batteries-included microservice toolkit for Crystal that mirrors and improves upon Go-Micro.
µCrystal provides a composable, opinionated framework with pluggable components for building blazing fast microservices with the safety of static typing and Ruby-like syntax ergonomics.
Table of Contents
Security
µCrystal prioritizes security by default:
- mTLS support out of the box
- JWT authentication middleware
- Role-based access control
- Built-in rate limiting and circuit breakers
For security vulnerabilities, please email security@watzon.tech.
Background
µCrystal aims to bring the excellent design patterns of Go-Micro to the Crystal ecosystem while leveraging Crystal's unique strengths:
- First-class async: Leverages Crystal's fibers and event loop instead of external reactors
- Compile-time safety: Uses macros and generics to generate stubs/clients and catch errors early
- Ruby-like ergonomics: Maintains the expressiveness Crystal developers love
- C-like performance: Achieves blazing fast execution speeds
The project follows a phased roadmap from v0.1 spike through v1.0 stable API, implementing core microservice patterns including service discovery, pub/sub messaging, observability, and authentication.
Install
Add this to your application's shard.yml
:
dependencies:
micro:
github: watzon/micro-crystal
Then run:
shards install
Usage
Create a simple microservice:
require "micro"
@[Micro::Service(name: "greeter", version: "1.0.0")]
class GreeterService
include Micro::ServiceBase
@[Micro::Method]
def hello(name : String) : String
"Hello #{name}"
end
end
# Override options if desired
options = Micro::ServiceOptions.new(
name: "greeter",
registry: Micro::Registries.memory,
server_options: Micro::ServerOptions.new(address: "0.0.0.0:8081")
)
GreeterService.run(options)
Service Discovery & Addressing
µCrystal supports multiple registries and a clear separation of bind vs. advertise addresses:
- In-memory registry: ideal for single-process development; process-local and not shared across binaries
- Distributed registries (e.g., Consul): use for multi-process or multi-host deployments
Programmatic setup with top-level factories:
require "micro"
registry = if addr = ENV["CONSUL_ADDR"]?
Micro::Registries.consul(Micro::Core::Registry::Options.new(type: "consul", addresses: [addr]))
else
Micro::Registries.memory
end
options = Micro::ServiceOptions.new(
name: "my-service",
registry: registry,
server_options: Micro::ServerOptions.new(
address: ENV["MICRO_SERVER_ADDRESS"]? || "0.0.0.0:8080",
advertise_address: ENV["MICRO_ADVERTISE_ADDRESS"]?
)
)
This separation enables:
- Container deployments (bind to 0.0.0.0, advertise container IP)
- NAT/load balancer scenarios (advertise public endpoint)
- Multi-NIC servers (choose which interface to advertise)
For a realistic, ergonomic dev workflow, the demo includes a single-process runner that starts multiple services and a gateway sharing one in-memory registry. When splitting into separate binaries, set CONSUL_ADDR
to switch to Consul.
Why µCrystal vs Lucky/Athena?
Lucky and Athena are excellent web frameworks for monolithic HTTP apps (routes/controllers/views). µCrystal is different by design:
- Microservice toolkit, not your typical web framework
- Service boundaries, discovery, and RPC between services are first-class
- Pluggable transports (HTTP/WebSocket today; others can be added)
- Built-in discovery, routing, and gateway
- Registries (memory, Consul) and selectors (round-robin, random)
- API gateway: routing DSL (Radix), method filters (expose/block), CORS, response transformations, aggregation routes, retries/circuit breaker
- OpenAPI generator (
/api/docs
), health, and Prometheus-style metrics (/metrics
)
- Async RPC and Pub/Sub out of the box
- Brokers (memory, NATS) for event-driven communication
- Macro annotations for services, methods, subscriptions
- Opinionated middleware pipeline
- Logging, timing, compression, rate limiting, JWT/mTLS, RBAC
- Observability
- Prometheus-style metrics with HTTP metrics server
- Connection pool metrics and request ID propagation
- Tracing scaffold (OpenTelemetry-ready)
- DX-first with compile-time safety
- Crystal macros generate handlers/clients and catch errors early
- Top-level
Micro::*
factories hide low-level plumbing
If you’re building a single web app with templates and controllers, Lucky or Athena may be a better fit. If you’re composing multiple services with discovery, messaging, and a gateway, µCrystal is the right choice.
API
High-level APIs are exposed under the Micro
namespace; low-level internals live under Micro::Core
and Micro::Stdlib
.
Micro::ServiceBase
— service lifecycle and handler integrationMicro::Transports
,Micro::Registries
,Micro::Codecs
,Micro::Brokers
— factories for pluggable componentsMicro::Gateway
— API gateway builder with routing DSL, OpenAPI generator (/api/docs
), health, metrics (/metrics
), CORS, transformations, aggregation, and auth
Annotations for macro-driven development:
@[Micro::Service]
— declare a service (name, version, middleware)@[Micro::Method]
— expose a method as RPC endpoint@[Micro::Subscribe]
— subscribe to broker topics
Documentation
- Getting started: docs/getting-started.md
- Guides: docs/guides/
- Concepts: docs/concepts/
- Reference: docs/reference/
Examples
- Hello world: examples/hello_world.cr
- Real-world demo (multi-service + gateway): see examples/demo/README.md
Maintainers
- @watzon - Chris Watson cawatson1993@gmail.com
Contributing
We welcome contributions! Please see our Contributing Guidelines (coming soon).
- Questions? Open an issue with the
question
label - Bug reports and feature requests welcome
- PRs accepted - please discuss major changes first
- All contributors must sign off on commits
Please follow the Crystal Code of Conduct.
License
Apache-2.0 © 2025 Chris Watson
See LICENSE for details.
micro-crystal
- 2
- 0
- 0
- 0
- 7
- 1 day ago
- August 9, 2025
Apache License 2.0
Mon, 11 Aug 2025 12:46:39 GMT