# scala-pet-store: the Java Pet Store rebuilt on the Typelevel stack

> scala-pet-store is a teaching implementation of the classic Java Pet Store in Scala, built with http4s, Circe, Doobie, Cats and tagless final, and organised so the domain package never mentions HTTP, JSON or JDBC.

**pauljamescleary/scala-pet-store** — An implementation of the java pet store using FP techniques in scala

- Repository: https://github.com/pauljamescleary/scala-pet-store
- Stars: 1,075 · Forks: 202
- Language: Scala
- License: Apache-2.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/pauljamescleary-scala-pet-store

## Why the Java Pet Store was ported at all

scala-pet-store is an implementation of the Java Pet Store using FP techniques in Scala, and the reason it exists is stated plainly. The goal is to demonstrate how to build an application using functional programming techniques in Scala, because when starting out in Scala from a Java background it was extremely difficult to piece together all of the little bits in order to make a cohesive whole application.

That framing sets the expectations correctly. This is a teaching artifact, and its value is in the shape of the code rather than in the pet store domain itself. The domain is deliberately the most boring one available, so that the only interesting thing on the page is the architecture.

The author is explicit that the audience is two groups at once. If you are an FP or TypeLevel contributor, he wants to know if something is not idiomatic, because he wants this to be an example of how things should be done. If you are an OO developer new to Scala, he wants to know if something is confusing, because he is trying to keep the project approachable. That dual invitation explains a lot about the code, including the parts that a pure functional project would have done differently.

The project is Apache-2.0 licensed, the last push was on 2026-04-13, and there are no published GitHub releases. The build is sbt, with build.sbt and a build.sh at the root, a project directory for the sbt configuration, and a .scalafmt.conf for formatting. The root also holds functional_test, a pet.json file, a post-pet.sh script for posting a pet, and a .mergify.yml for automating dependency merges.

## The stack, and why each piece was chosen

The library choices are given with reasons, which is unusual and useful in a reference project.

Http4s is the web server. The author notes he could have gone with finch, twitter server, or akka-http, but had been interested in learning http4s.

Circe handles JSON serialization, Doobie handles database access, and Circe Config handles application configuration, with the stated benefit of a neat mapping of config file to case classes so there is no code to write for that mapping.

Cats is listed for FP awesomeness, and ScalaCheck for property based testing. The core domain uses tagless final.

The set is the Typelevel stack, and the project says the author is working with it initially to see how far he can go. What that means in practice is that the whole application is built from cats-effect IO for effects, tagless final for the algebra abstraction, and the http4s service layer on top.

The repository layout matches. There is a src directory for the main code, a functional_test directory, an AUTHORS.md with the contributors, a CODE_OF_CONDUCT.md, and a .github directory for the workflow that produces the build badge.

The status section is the honest bit. Most of the endpoints are in place, and there are a few big pieces remaining: a ScalaJS React front end, tests built using ScalaCheck in an idiomatic sane way, and a microsite documenting the patterns in the pet store, described as a kind of mini-book. So the code is there to read, but the teaching material around it is not finished, and the ScalaCheck work is the piece that would matter most if you were copying the testing approach rather than the architecture.

## How the domain package is kept free of the outside world

The architectural core of the project is a DDD and onion architecture split into three packages, and the README explains each with a specific reason.

Domain driven design is described as being about developing a ubiquitous language, a language you can use to discuss your software with people who do not know programming, and the key concept is that the language surfaces in your code. If you talk about a Pet, you should see a Pet in the code.

The mechanism for that is keeping the domain pure. The domain package is deliberately free of JDBC, JSON, HTTP and the rest. A Transaction in banking relies on a Debit and a Credit, and those concepts should surface in the domain, but HTTP, JDBC and SQL are not essential to the domain, so you decouple them as much as possible.

Inside the domain there are three concepts. `Service` is the coarse grained use case that works with other domain concepts to realise your use case. `Repository` is a way to get data into and out of persistent storage, and the README is emphatic about its constraints: repositories do not have any business logic in them, they should not know about the context in which they are used, and they should not leak details of their implementations into the world. It is described as kind of like an interface in Java, a trait to be implemented elsewhere.

The third is `models`, things like `Pet`, `Order` and `User`, which are kept lean and free of behaviour. All of the behaviour comes via `Validations` and `Services`.

So the domain package is a set of traits and pure data, and the implementation of the traits lives somewhere else entirely. That is the whole point of the layout, and it is the first thing worth reading in the repository if you want to understand how the project teaches.

## Infrastructure, config, and where the CRUD endpoints land

The infrastructure package is where the ugliness lives, and the README names it that way. It has HTTP things and JDBC things.

Inside it there are two directories. The `endpoint` package contains the HTTP endpoints surfaced via http4s, and JSON handling via Circe also lives there. The `repository` package contains the JDBC code, the implementations of the Repositories, and there are two of them, an in-memory version and a doobie version.

That duplication is the design working as intended. The domain declares the Repository trait, the infrastructure provides two implementations, and the application can be run against the in-memory one for tests and the Doobie one against a real database, with nothing in the domain changing.

The config package could be considered infrastructure, since it has nothing to do with the domain, and it uses Circe Config to load configuration objects when the application starts up.

The domain package itself uses `Services` as coarse-grained interfaces to the domain, and these typically represent real-world use cases. The README notes there is a lot of CRUD in the pet store, but use cases can be things like withdrawal or register in other domains, and that you often see a one-to-one mapping of Services to Endpoints, the HTTP API calls the application surfaces. That one-to-one mapping is a property of this domain, not a rule the architecture imposes, and it is the reason the pattern looks cleaner here than it would in a domain with richer use cases.

One more piece of the design is the dependency injection approach, and it is a deliberate compromise. The pet store uses `classes` for certain things, and the author notes some would argue that is not very FP. There are lots of ways to do dependency injection, including function arguments, implicits and monad transformers. Using class constructors is rather OO, but the author believes it is simpler for people with OO backgrounds to digest. The README then says there is no Spring, no Guice, and no other DI framework, which is the point: the dependency graph is visible in the constructor signatures rather than in a container configuration.

## What the project is not yet, and how to use it anyway

The first limitation is completeness, and the project says so. Most of the endpoints are in place, and the three missing pieces are a ScalaJS React front end, idiomatic ScalaCheck tests, and the documentation microsite. So the reference implementation of the patterns exists in code but not yet in prose, and the property-based testing that the stack implies is not the reference implementation a reader would want to copy.

The second limitation is the tension the author keeps returning to. The project embraces some traditional OO concepts in addition to modern FP concepts and libraries, and the dependency injection choice is the clearest example. A reader who wants a purely functional reference will find classes where they expected typeclasses, and a reader who wants idiomatic Java-style layering will find Tagless Final where they expected interfaces. The project is deliberately trying to satisfy both, and that means neither community will find it exactly as they would write it.

The third limitation is that the domain is trivial. A pet store is CRUD, and CRUD does not exercise the parts of an architecture that get hard: transactions spanning aggregates, eventual consistency, authorisation inside the domain, concurrency. The pattern transfers, the difficulty does not.

Given those limits, the way to use the project is as a reference for one specific thing: how the layers are separated and where each decision belongs. Read the domain package first, then the infrastructure package, and notice that the domain does not change when you swap the repository implementation. The functional_test directory and the pet.json and post-pet.sh files at the root suggest there is a way to exercise the thing end to end, and the gitter chat linked from the README is where the author is looking for feedback on whether the techniques are landing.

The build status badge and the AUTHORS.md contributor list are the two places to check who is currently working on the project, and the README credits Zak Patterson as also maintaining it.

## Conclusion

scala-pet-store fits a Java developer moving to Scala who wants one coherent example of how the pieces fit together rather than a tour of isolated snippets, and it fits a functional programmer who wants to see whether a Typelevel stack stays approachable. It is a poor fit as a starting point for a production service, because the project states most endpoints are in place with large pieces remaining, including a ScalaJS React front end, idiomatic ScalaCheck tests and a documentation microsite. Before using it as a reference, read the domain package and the infrastructure package side by side, since the separation between them is the lesson the project is teaching, and check the AUTHORS.md contributors list to see who has worked on which part.

## FAQ

### What is scala-pet-store?

It is an implementation of the Java Pet Store using FP techniques in Scala, created to demonstrate how to build an application using functional programming techniques in Scala, because piecing the little bits together from a Java background was difficult.

### Which libraries does scala-pet-store use?

The Typelevel stack. Http4s for the web server, Circe for JSON serialization, Doobie for database access, Circe Config for application config, Cats for FP abstractions, ScalaCheck for property based testing, and tagless final for the core domain.

### How is the scala-pet-store project structured?

Into three packages. The domain package holds Service traits, Repository traits and lean models, and is deliberately free of JDBC, JSON and HTTP. The infrastructure package holds the http4s endpoints with Circe and the repository implementations, an in-memory one and a doobie one. The config package loads configuration at startup with Circe Config.

### What is still missing from scala-pet-store?

The project states that most of the endpoints are in place and lists three remaining pieces: a ScalaJS React front end, tests built using ScalaCheck in an idiomatic sane way, and a microsite documenting the patterns in the pet store, described as a kind of mini-book.

### How does scala-pet-store handle dependency injection?

It uses class constructors for certain things, which the author acknowledges is not very FP, on the grounds that there are many ways to do dependency injection, including function arguments, implicits and monad transformers, and that class constructors are simpler for people with OO backgrounds. There is no Spring, Guice or other DI framework in the project.

## Sources

- [Issues](https://github.com/pauljamescleary/scala-pet-store/issues)
- [License: Apache-2.0](https://github.com/pauljamescleary/scala-pet-store/blob/master/LICENSE)
- [pauljamescleary/scala-pet-store on GitHub](https://github.com/pauljamescleary/scala-pet-store)
- [README](https://github.com/pauljamescleary/scala-pet-store/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pauljamescleary-scala-pet-store
