app
Version, currently main branch1 version
- main branchlatestOct 9, 2026
github.com/stijnwtf/crystal-api-starter
๐ Modern Crystal JSON API starter: Kemal, typed JSON, specs, Ameba linting and a static binary in a FROM scratch Docker image.
1 stars
0 dependents
License: MIT
Installation
# Add this to your shard.yml
dependencies:
app:
github: stijnwtf/crystal-api-starter
branch: mainmain is a branch, not a release, so this tracks it rather than pinning a version.
Then run:
shards installshard.yml
- Crystal
>= 1.21.0- License
- MIT
- Target
appfrom src/app.cr
Dependencies
Runtime Dependencies
- kemal~> 1.14github: kemalcr/kemal
Development Dependencies
- ameba*github: crystal-ameba/amebadev
- spec-kemal*github: kemalcr/spec-kemaldev
README
What's inside
| ๐ Kemal | Fast, Sinatra-style routing |
| ๐งฑ Typed JSON | JSON::Serializable models and request structs, validation with clear errors |
| ๐ Thread-safe store | In-memory, mutex-guarded, easy to swap for Postgres or SQLite |
| ๐งช Specs | Request specs with spec-kemal |
| ๐งน Linting | Ameba + crystal tool format |
| ๐ณ Docker | Static binary in a FROM scratch image |
| ๐ค CI | Format, lint, specs and Docker build on every push |
Quick start
git clone https://github.com/stijnwtf/crystal-api-starter my-api
cd my-api
shards install
crystal run src/app.cr # http://localhost:3000
Needs Crystal 1.21+ (brew install crystal).
$ curl -X POST localhost:3000/tasks -d '{"title":"Try Crystal"}'
{"id":1,"title":"Try Crystal","completed":false,"created_at":"2026-10-09T09:29:56Z"}
Commands
| Command | Does |
|---|---|
make dev | Run with auto-restart (watchexec) |
make test | Run specs |
make lint | Run Ameba |
make format | Format code |
make build | Optimized binary in bin/app |
make docker | Build the production image |
API
| Method | Path | Body | Response |
|---|---|---|---|
GET | /health | {"status","version"} | |
GET | /tasks | Task[] | |
GET | /tasks/:id | Task or 404 | |
POST | /tasks | {"title"} | 201 Task, 400 or 422 |
PATCH | /tasks/:id | {"title"?, "completed"?} | Task, 404 or 422 |
DELETE | /tasks/:id | 204 or 404 |
Structure
src/
โโโ app.cr entry: config, JSON error handlers, server start
โโโ store.cr thread-safe in-memory store
โโโ models/task.cr Task model, request bodies, validation
โโโ routes/ one file per resource
spec/ request specs
Add a resource: create src/models/thing.cr and src/routes/things.cr. Both folders are required with a glob, so no wiring needed.
Deploy
docker build -t my-api .
docker run -p 3000:3000 my-api
Configure the port with PORT (default 3000).
If this saved you time, a โญ๏ธ helps others find it.
License
Documentation
Built from the current release. The first visit to a release nobody has asked for starts its build.
Links
This branch
- Branch
main- Seen
- Oct 9, 2026
- Crystal
>= 1.21.0- Indexed
- yes
Dependents
No indexed shard depends on this one yet.
Repository
github.com/stijnwtf/crystal-api-starter
Metadata
- Created
- Oct 10, 2026
- Updated
- Oct 20, 2026
- Synced
- Oct 20, 2026
- Versions
- 1