skip to content

What is the Repository marker interface in Spring Data, and how does CrudRepository relate to it?

level: juniorimportance: must knowfreq 70%

answer

  1. Repository = empty marker + type capture
  2. T = entity, ID = key
  3. CrudRepository adds save/find/delete
  4. findAll returns Iterable not List
  5. proxy backed by SimpleJpaRepository

basics

~20 s

Repository<T, ID> is an empty marker interface that tells Spring Data an interface is a repository and captures the entity type T and its id type ID. CrudRepository extends it and adds ready-made save/find/delete methods.

solid answer

~40 s

Repository<T, ID> is the root of Spring Data's repository hierarchy. It declares no methods — it is a pure marker (technically a generic-typing) interface. Its only job is to (a) flag an interface so Spring Data's classpath scanning creates a proxy implementation for it at runtime, and (b) capture two type parameters: T, the domain/entity type, and ID, its identifier type. You rarely extend Repository directly. Instead you extend CrudRepository<T, ID>, which builds on Repository and supplies generic CRUD operations: save, saveAll, findById, existsById, findAll, findAllById, count, deleteById, delete, deleteAll. You write no implementation — Spring Data generates the proxy backed by a store-specific base class (e.g. SimpleJpaRepository). This is the whole point of Spring Data: declare an interface, get an implementation for free.

code

java · 15 lines
java
public interface UserRepository extends CrudRepository<User, Long> {
    // Inherited for free: save, findById, findAll, deleteById, count, ...
    // Plus a derived query — implemented from the method name:
    Optional<User> findByEmail(String email);
}

// Usage — no implementation class written anywhere:
@Service
class UserService {
    private final UserRepository repo;
    UserService(UserRepository repo) { this.repo = repo; }

    User register(User u) { return repo.save(u); }
    Iterable<User> all()  { return repo.findAll(); } // Iterable, not List
}

go deeper

for a junior

Know Repository is the empty marker, CrudRepository gives CRUD for free, and you only declare an interface.

for a middle

Explain type capture (T/ID), that findAll returns Iterable, and that a store-specific proxy provides the implementation.

for a senior

Discuss extending Repository directly for minimal surface, @NoRepositoryBean on the base interfaces, and Commons vs JPA module split.

for a principal

Reason about interface-surface design as API governance — exposing only the operations a repository should offer rather than defaulting to broad CRUD.

## The hierarchy Spring Data organizes its repository interfaces as a layered hierarchy so you can pick exactly the capabilities you want. **`Repository<T, ID>`** is the root. It is a *marker interface* — an interface with **no methods at all**. Its two responsibilities: 1. **Discovery**: When Spring Data scans the classpath (triggered by `@EnableJpaRepositories`, Spring Boot auto-config, etc.), any interface that (transitively) extends `Repository` is picked up, and a **dynamic proxy** implementing it is created and registered as a Spring bean. An interface that does *not* extend `Repository` (and is not annotated `@RepositoryDefinition`) is invisible to Spring Data. 2. **Type capture**: The generics `T` (the domain/entity type, e.g. `User`) and `ID` (the id type, e.g. `Long`) tell Spring Data what entity this repository manages and what its primary-key type is. Query derivation, `findById`, etc. all rely on these. **`CrudRepository<T, ID>`** `extends Repository<T, ID>` and declares the generic CRUD methods: - `<S extends T> S save(S entity)` and `saveAll(Iterable)` - `Optional<T> findById(ID id)`, `boolean existsById(ID id)` - `Iterable<T> findAll()`, `Iterable<T> findAllById(Iterable<ID> ids)` - `long count()` - `void deleteById(ID id)`, `void delete(T entity)`, `void deleteAllById(...)`, `void deleteAll(...)`, `void deleteAll()` Note `findAll()` returns **`Iterable<T>`**, not `List<T>` — a deliberate lowest-common-denominator choice (some stores stream). Spring Data 3.0 added `ListCrudRepository` if you want `List` back. ## Where the implementation comes from You never write an `implements` class. At runtime Spring Data creates a proxy whose CRUD methods are backed by a **store-specific base implementation**: `SimpleJpaRepository` for JPA, `SimpleMongoRepository` for MongoDB, etc. Derived query methods (`findByEmail`) are parsed from the method name and implemented on the fly. ## Gotchas - `Repository` being empty means extending it alone gives you **zero** methods — you'd add only derived/`@Query` methods. That's a valid, minimal-surface choice for read-only or narrowly-scoped repositories. - The interface itself is annotated `@NoRepositoryBean` so Spring never tries to instantiate `Repository`/`CrudRepository` directly (see the related question). - `CrudRepository` is store-agnostic — it lives in `org.springframework.data.repository` (Spring Data Commons), not in the JPA module. `JpaRepository` is the JPA-specific extension.

  • Why does findAll() return Iterable<T> rather than List<T>?
    Iterable is the lowest common denominator across stores — some can stream results without materializing a full list. Spring Data 3.0 added ListCrudRepository whose findAll returns List for convenience.
  • If you extend Repository directly instead of CrudRepository, what methods do you get?
    None — Repository is empty. You'd only get the derived/@Query methods you declare yourself, which is useful to expose a minimal, controlled API surface.

saying these in an interview costs you the question

  • Claiming Repository has save/find/delete methods (it's empty)
  • Saying findAll returns List<T>
  • Thinking you must write an implements class for CrudRepository

context