What is @NoRepositoryBean and when must you use it?
answer
- skip proxy creation for this interface
- put on shared/generic base interfaces
- framework base interfaces all use it
- NOT inherited — only the annotated interface
- never on concrete repos (breaks injection)
basics
~20 s@NoRepositoryBean marks a repository interface as a base/intermediate interface that Spring Data should NOT create a bean/proxy for. You put it on shared base interfaces you extend but never use directly, so Spring doesn't try to instantiate them.
solid answer
~50 s@NoRepositoryBean tells Spring Data's repository scanning to skip proxy creation for a given repository interface. Spring Data creates a bean for every interface extending Repository — but sometimes you define an intermediate base interface that other repositories extend (e.g. a MyBaseRepository<T, ID> exposing shared custom methods across all your repositories). That base isn't tied to a concrete entity and should never be instantiated on its own. Without @NoRepositoryBean, Spring Data would try to create a proxy for it and either fail or register a useless/ambiguous bean. Annotating the base with @NoRepositoryBean excludes it from instantiation while still letting concrete sub-interfaces inherit its methods. This is exactly why the framework's own base interfaces — Repository, CrudRepository, PagingAndSortingRepository, JpaRepository — are all annotated @NoRepositoryBean. It is not inherited: only the specific interface it's placed on is skipped.
code
java · 17 lines// Shared base — extended by all repos, never instantiated itself.
@NoRepositoryBean
public interface BaseRepository<T, ID> extends JpaRepository<T, ID> {
default T getByIdOrThrow(ID id) {
return findById(id).orElseThrow(() ->
new EntityNotFoundException("Not found: " + id));
}
}
// Concrete repository — NO @NoRepositoryBean; this one gets a proxy bean.
public interface UserRepository extends BaseRepository<User, Long> {
Optional<User> findByEmail(String email);
}
// Injected normally; getByIdOrThrow + findByEmail both available.
// If BaseRepository lacked @NoRepositoryBean, startup would fail trying
// to build a proxy for the generic, entity-less base interface.go deeper
Know it stops Spring from creating a bean for a base interface you only extend.
Explain the custom-base-repository use case and that framework interfaces like CrudRepository use it.
Know it's not inherited, the failure modes of misuse, and pairing it with repositoryBaseClass for shared implementations.
Design cross-cutting repository behavior (soft delete, auditing, tenant scoping) via a @NoRepositoryBean base plus custom base class, weighing it against fragment interfaces.
## The mechanism it controls Spring Data's repository infrastructure scans for interfaces extending `Repository` and creates a **proxy bean** for each one. That's usually what you want — one bean per concrete repository. But the hierarchy also contains **intermediate base interfaces** that must **not** become beans. **`@NoRepositoryBean`** (in `org.springframework.data.repository`) is a marker annotation placed on a repository interface to tell the scanner: *do not create an instance/proxy for this exact interface.* ## The classic use case: a custom base repository Suppose you want a method available on **every** repository in your app — say `Optional<T> findByIdOrThrow(ID id)` or a soft-delete helper. You create a generic base interface and put your shared methods there, then have each concrete repository extend it: ```java @NoRepositoryBean public interface BaseRepository<T, ID> extends JpaRepository<T, ID> { T getByIdOrThrow(ID id); } ``` This interface: - is **generic** (`T`, `ID` are unbound) — it isn't tied to any concrete entity, so Spring Data can't (and shouldn't) build a proxy for it; - is meant to be **extended, not used directly**. Without the annotation, the scanner sees `BaseRepository extends Repository` and tries to instantiate it, causing a startup error (it has no domain type to bind) or a spurious bean. `@NoRepositoryBean` cleanly excludes it. Concrete children (`UserRepository extends BaseRepository<User, Long>`) still inherit `getByIdOrThrow` and *do* get proxied. You'd typically pair this with a custom base **implementation** class registered via `repositoryBaseClass` on `@EnableJpaRepositories`. ## Why the framework's own interfaces use it Every shared interface in the hierarchy is annotated `@NoRepositoryBean`: `Repository`, `CrudRepository`, `ListCrudRepository`, `PagingAndSortingRepository`, `ListPagingAndSortingRepository`, `JpaRepository`, `SimpleJpaRepository`'s interface, etc. Otherwise Spring Data would try to instantiate `CrudRepository` itself. ## Key semantics & gotchas - **Not inherited**: `@NoRepositoryBean` applies **only** to the exact interface it annotates. A sub-interface without the annotation is still eligible for proxying — which is precisely what you want (base excluded, concrete children included). Never put it on your concrete `UserRepository` or you'll get no bean and an autowiring failure. - **Symptom of misuse**: If you forget it on a base interface, you may see `BeanCreationException` / errors about not being able to determine the domain type, or an unexpected extra repository bean. - **Alternative for the opposite direction**: `@RepositoryDefinition` lets an interface that does *not* extend `Repository` still be treated as a repository — the inverse tool. - It changes **nothing at runtime behavior** for the concrete repositories; it's purely a scan-time exclusion flag. ## When to use - On any generic/shared intermediate repository interface you introduce to centralize methods or plug in a custom base implementation. - Never on a concrete, entity-bound repository you actually inject.
- Is @NoRepositoryBean inherited by sub-interfaces?No — it applies only to the exact interface it annotates. That's intentional: the generic base is excluded while concrete children (without the annotation) are still proxied and injectable.
- What happens if you accidentally put @NoRepositoryBean on your concrete UserRepository?Spring Data won't create a bean for it, so any attempt to @Autowire UserRepository fails with a NoSuchBeanDefinitionException / unsatisfied-dependency error at startup.
- How do you add a shared custom implementation behind such a base interface?Provide a base implementation class extending SimpleJpaRepository and register it via repositoryBaseClass on @EnableJpaRepositories, so all repositories inherit the behavior.
saying these in an interview costs you the question
- Saying it's inherited by all sub-interfaces
- Putting it on concrete repositories
- Claiming it changes runtime CRUD behavior rather than scan-time proxy creation
- Confusing it with @RepositoryDefinition (the inverse)