Comparative example: the same API implemented in Crystal (Kemal) and Go (Gin).
- Crystal >= 1.17
- Go >= 1.22
- SQLite3 CLI (for seeding)
- wrk (for load testing)
- Seed data from the repository root:
sqlite3 posts.db < db/seed.sql- Location:
posts.dbis created at the repository root. The Crystal service runs from the repo root, the Go service runs fromgo/. Go uses../posts.dbby default to point to the root database file.
- Create database (one of):
createdb posts
# or
psql -h localhost -U postgres -c "CREATE DATABASE crystal-vs-go;"- Seed from the repository root:
export DATABASE_URL="postgres://postgres:postgres@localhost:5432/crystal-vs-go?sslmode=disable"
psql "$DATABASE_URL" -f db/seed.sqlNotes:
- The seed script is portable and works for both SQLite and PostgreSQL.
- Both apps read the database from
DATABASE_URL. Usepostgres://...for Postgres orsqlite3:/absolute/path/to/posts.dbfor SQLite.
Sources live under crystal/.
Run:
cd crystal
shards install
crystal run src/main.cr
# Test
curl http://localhost:3000/
curl http://localhost:3000/postsConfiguration:
- Default DB URL:
sqlite3:./posts.db(setDATABASE_URLtopostgres://...for Postgres) - Override:
DATABASE_URL=sqlite3:/absolute/path/posts.db crystal run src/main.cr
Sources live under go/.
Run:
cd go
go mod tidy
go run .
# Test
curl http://localhost:8080/
curl http://localhost:8080/postsConfiguration:
- Default DSN:
../posts.db(relative togo/directory) - SQLite:
DATABASE_URL=sqlite3:../posts.db go run . - Postgres:
DATABASE_URL=postgres://postgres:postgres@localhost:5432/posts?sslmode=disable go run .
crystal/: Crystal app (Kemal)go/: Go app (Gin)db/seed.sql: seed script for users and posts (5 posts per user)posts.db: SQLite database file at repo root
Crystal (port 3000):
wrk -c 100 -d 30 http://localhost:3000/postsGo (port 8080):
wrk -c 100 -d 30 http://localhost:8080/posts