Question
CrudRepository vs JpaRepository in Spring Data JPA
Question
In Spring Data JPA, what is the difference between the CrudRepository and JpaRepository interfaces?
They often seem to be used interchangeably in examples, so it can be unclear what each one is for.
Why would you choose one over the other, and what additional features does JpaRepository provide compared with CrudRepository?
Short Answer
By the end of this page, you will understand how CrudRepository and JpaRepository are related, what methods each one provides, and when to choose the simpler interface versus the more feature-rich one in a Spring Data JPA application.
Concept
CrudRepository and JpaRepository are both repository interfaces from the Spring Data ecosystem, but they serve slightly different levels of functionality.
At a high level:
CrudRepositorygives you the basic Create, Read, Update, Delete operations.JpaRepositoryincludes everything fromCrudRepositoryand adds extra features that are useful specifically for JPA-based applications.
The inheritance relationship
JpaRepository is not completely separate. It builds on smaller repository interfaces.
The hierarchy is roughly:
Repository
└── CrudRepository
└── PagingAndSortingRepository
└── JpaRepository
That means:
- If you use
JpaRepository, you also get all methods fromCrudRepository JpaRepositoryis a more specialized interface for JPACrudRepositoryis the minimal common choice when you only need basic data access
What CrudRepository provides
Mental Model
Think of these interfaces like toolboxes:
CrudRepositoryis a basic toolbox with the essential tools: save, find, delete, count.JpaRepositoryis a larger toolbox that includes the basic tools plus advanced ones for JPA-specific tasks.
If all you need is a screwdriver and a hammer, the small toolbox is enough. If you also need a wrench set, measuring tape, and specialized tools, the larger toolbox saves time.
Both can do the basic job. The difference is how many built-in tools you want available.
Syntax and Examples
A repository interface in Spring Data JPA is usually declared by extending one of the Spring Data repository interfaces.
Using CrudRepository
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Long> {
}
This gives you basic methods like:
userRepository.save(user);
userRepository.findById(1L);
userRepository.findAll();
userRepository.deleteById(1L);
Using JpaRepository
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
This gives you all CRUD methods plus JPA-specific ones like:
userRepository.saveAndFlush(user);
userRepository.findAll(); // returns List<User>
userRepository.flush();
userRepository.deleteAllInBatch();
Example entity
Step by Step Execution
Consider this repository:
public interface UserRepository extends JpaRepository<User, Long> {
}
And this service code:
User user = new User(1L, "Ava");
userRepository.save(user);
List<User> users = userRepository.findAll();
userRepository.flush();
What happens step by step
-
new User(1L, "Ava")- A new Java object is created in memory.
-
userRepository.save(user)- Spring Data delegates the save operation to the JPA provider.
- If the entity is new, it will be inserted.
- If it already exists, it may be updated.
-
userRepository.findAll()- A query is executed to fetch all
Userrows. - Because this is
JpaRepository, the result is returned as aList<User>.
- A query is executed to fetch all
Real World Use Cases
Here are common situations where these interfaces appear in real applications.
When CrudRepository is enough
- A small internal app with simple create, read, update, delete screens
- A microservice that only stores and fetches records by ID
- A codebase where the team wants to expose only minimal repository operations
- Teaching or learning examples focused only on basic persistence
When JpaRepository is more useful
- Applications that need pagination and sorting often
- Services that work with JPA-specific behavior like flushing or batch deletes
- Admin dashboards that list many records and need
Listresults directly - Larger enterprise apps where repository convenience methods save development time
Example scenarios
- User management system:
JpaRepositoryis convenient because you may need paging, sorting, and bulk operations. - Simple key-value style entity storage:
CrudRepositorymay be enough. - Order processing app:
JpaRepositorycan help when flushing changes before later transaction logic depends on them.
Real Codebase Usage
In real projects, developers often choose a repository interface based on how much behavior they want available by default.
Common pattern: use JpaRepository as the default
Many Spring Boot applications use:
public interface OrderRepository extends JpaRepository<Order, Long> {
}
Why?
- It is convenient
- It returns
Listfor common methods - It supports pagination and sorting through inherited interfaces
- It exposes JPA-specific helper methods
Common pattern: use a smaller interface intentionally
Some teams prefer:
public interface ProductRepository extends CrudRepository<Product, Long> {
}
This can help:
- keep APIs smaller
- reduce accidental misuse of advanced methods
- make the repository contract more focused
Validation and service-layer usage
Repositories are usually called from a service layer:
@Service
{
UserRepository userRepository;
{
.userRepository = userRepository;
}
User {
(user.getName() == || user.getName().isBlank()) {
();
}
userRepository.save(user);
}
}
Common Mistakes
1. Thinking they are unrelated interfaces
A common misunderstanding is assuming you must choose between two completely separate repository systems.
In reality, JpaRepository extends the simpler repository interfaces.
2. Expecting CrudRepository.findAll() to return a List
Broken assumption:
CrudRepository<User, Long> repo = null;
List<User> users = repo.findAll(); // compile-time problem
Why it fails:
CrudRepository.findAll()returnsIterable<User>JpaRepository.findAll()returnsList<User>
Correct approach:
Iterable<User> users = repo.findAll();
Or use JpaRepository if a List is what you want.
3. Using JpaRepository methods when the repository only extends CrudRepository
Comparisons
Repository interface comparison
| Interface | Purpose | Key return types | Extra features | Best when |
|---|---|---|---|---|
CrudRepository | Basic CRUD operations | Often Iterable<T> | Save, find, delete, count, exists | You want a minimal repository API |
PagingAndSortingRepository | CRUD plus paging and sorting | Iterable<T> | findAll(Sort sort), pagination support | You need paging but not necessarily full JPA helpers |
JpaRepository | Full JPA-oriented repository | Often List<T> |
Cheat Sheet
Quick reference
CrudRepository
public interface UserRepository extends CrudRepository<User, Long> {
}
Common methods:
save(entity)
findById(id)
findAll()
deleteById(id)
count()
existsById(id)
Notes:
- Minimal API
findAll()returnsIterable<T>- No
flush()or batch JPA helpers
JpaRepository
public interface UserRepository extends JpaRepository<User, Long> {
}
Includes everything from CrudRepository plus:
findAll() // returns List<T>
flush()
saveAndFlush(entity)
deleteAllInBatch()
deleteAllByIdInBatch(ids)
getReferenceById(id)
Notes:
FAQ
What is the main difference between CrudRepository and JpaRepository?
CrudRepository provides basic CRUD operations. JpaRepository includes those operations and adds JPA-specific features such as flush(), saveAndFlush(), batch deletes, and List-based find methods.
Is JpaRepository a subtype of CrudRepository?
Yes. JpaRepository extends other Spring Data repository interfaces, including CrudRepository, so it includes all CRUD methods.
Should I always use JpaRepository in Spring Boot?
Not always, but many projects do because it is convenient. If you only need simple CRUD and want a smaller API, CrudRepository is still a good choice.
Why does findAll() return different types?
With CrudRepository, findAll() returns Iterable<T>. With , it returns , which is often easier to use in application code.
Mini Project
Description
Build a small Spring Data JPA repository layer for a Book entity to see the practical difference between CrudRepository and JpaRepository. This project demonstrates basic CRUD operations first, then shows how switching to JpaRepository gives you extra convenience like List results and flush() support.
Goal
Create a repository for books, save and read records, then compare what changes when the repository extends CrudRepository versus JpaRepository.
Requirements
- Create a JPA entity named
Bookwithidandtitlefields. - Define a repository interface for
Bookand test basic save and find operations. - Show one version using
CrudRepositoryand one version usingJpaRepository. - Demonstrate at least one method that exists in
JpaRepositorybut not in .
Keep learning
Related questions
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Choosing a @NotNull Annotation in Java: Validation vs Static Analysis
Learn how Java @NotNull annotations differ, when to use each one, and how to choose between validation, IDE hints, and static analysis tools.
Convert a Java Stack Trace to a String
Learn how to convert a Java exception stack trace to a string using StringWriter and PrintWriter, with examples and common mistakes.