skip to content

Interface-Based Projections

Declaring an interface of getters makes Spring Data select just those columns, while open projections with SpEL give up that optimization. Interviewers ask because fetching whole entities to render three fields is a routine performance mistake.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is an interface-based projection in Spring Data, and why would you use one instead of returning the full entity?

level: juniorimportance: must knowfreq 72%

answer

  1. Interface with getters = return type
  2. Spring builds a dynamic proxy per row
  3. Closed = narrows SELECT columns
  4. Read model, not managed entity
  5. Less boilerplate than DTO class

basics

~20 s

An interface-based projection is a plain Java interface with getters. You declare it as a repository method's return type; Spring Data returns proxies exposing only those getters, so you fetch just the columns you need instead of the whole entity.

solid answer

~40 s

An interface-based projection is a Java interface whose getters name the entity properties you want. You use it as a query method's return type (e.g. List<UserView> findByActiveTrue()). Spring Data builds a dynamic proxy backed by the query result and exposes only the declared getters. The main benefits: you fetch fewer columns (a 'closed' projection lets Spring narrow the SELECT to just those properties), you avoid loading lazy associations you don't need, and you return a lightweight read model to the API without exposing the JPA entity. It's ideal for read-heavy list/detail views where you don't need managed entities, dirty checking, or every column. Contrast with class-based (DTO) projections, which use a constructor instead of a proxy.

code

java · 10 lines
java
// Projection interface
interface UserView {
    String getUsername();
    String getEmail();
}

// Repository
interface UserRepository extends JpaRepository<User, Long> {
    List<UserView> findByActiveTrue();   // returns proxies, not entities
}

go deeper

for a junior

Know it's an interface of getters used as a return type, and that it fetches only the fields you need.

for a middle

Explain the dynamic-proxy mechanism and the closed-vs-open distinction that governs column optimization.

for a senior

Position it against DTO/class projections and dynamic projections; articulate when a read model beats returning an entity.

for a principal

Weigh projections in an API contract strategy: decoupling persistence from transport, avoiding entity leakage, and query-cost implications at scale.

## What it is A **projection** is a way to have a Spring Data repository return a subset of an entity's data rather than the full managed entity. An **interface-based projection** is simply a Java **interface** (not a class) that declares getter methods matching the entity's property names. ```java interface UserView { String getUsername(); String getEmail(); } ``` You then use that interface as the **return type** of a repository query method: ```java interface UserRepository extends JpaRepository<User, Long> { List<UserView> findByActiveTrue(); } ``` At runtime Spring Data creates a **dynamic proxy** for each result row. The proxy is backed by the query results and forwards each getter call to the underlying data. You never write an implementation class — Spring generates it. ## Why use it 1. **Fetch fewer columns.** For a *closed* projection (all getters map directly to entity properties), Spring Data can narrow the generated `SELECT` to only the referenced columns instead of `SELECT *`. This reduces I/O and avoids touching large/blob columns. 2. **Avoid loading unneeded associations.** You don't trigger lazy relationships you don't reference. 3. **Return a read model, not the entity.** You hand the web/API layer a stable, minimal view without leaking JPA entities (no accidental lazy-loading, no `@Entity` coupling, no dirty-checking overhead). 4. **Less boilerplate than a DTO class.** No constructor, no field wiring — just an interface. ## Key terms - **Managed entity**: an object tracked by the JPA persistence context, subject to dirty checking and lifecycle. Projections are *not* managed — they're read-only value views. - **Closed projection**: every getter corresponds to an entity property. Spring knows exactly which columns are needed and optimizes the query. - **Open projection**: at least one getter uses `@Value` with a SpEL expression, so Spring can't tell which columns are needed and fetches the whole entity. ## When to use Read-heavy endpoints, list/table views, dropdown data, dashboards — anywhere you need a slice of the entity and don't need to modify it. When you need to *modify* data, load the entity itself. ## Gotchas - Getter names must match entity property names exactly (closed projection) or Spring can't resolve them. - Projections returned from JPQL/native queries have caveats (native queries need column aliases matching the getter names). - An interface projection is read-only; you can't persist changes through it.

  • Is a projection proxy a managed JPA entity?
    No. It's a read-only view backed by the query result; it's not tracked by the persistence context, has no dirty checking, and you cannot persist changes through it.
  • How does Spring know which columns to fetch for a projection?
    For a closed projection it inspects the getter names, maps them to entity properties, and narrows the SELECT to just those columns. For an open projection it can't determine that, so it fetches the whole entity.

context

open as a page

What is the difference between a closed and an open interface projection, and how does each affect the generated SQL?

level: middleimportance: must knowfreq 68%

basics

~20 s

Closed projections have only plain getters that map to entity properties, so Spring narrows the SELECT to just those columns. Open projections use @Value with SpEL (or default methods computing values), so Spring can't optimize and fetches the whole entity.

open as a page

How do nested interface projections work, and what determines whether the associated data is fetched efficiently?

level: seniorimportance: should knowfreq 48%

basics

~20 s

A getter can return another projection interface, so you project across associations. Spring resolves the nested interface's getters against the associated entity. Nesting works cleanly for closed projections built from entity properties; native/complex queries and open expressions can break the optimization.

open as a page

When would you choose an interface projection versus a class-based (DTO) projection, and what are dynamic projections?

level: seniorimportance: should knowfreq 52%

basics

~20 s

Interface projections use proxies and getters and support open/nested projections. Class (DTO) projections use a constructor and give you a concrete, serializable value type. Dynamic projections let one repository method return different projection types via a Class<T> parameter.

open as a page

You added a closed interface projection but the SQL still selects all columns. What are the likely causes, and how do you guarantee column narrowing?

level: principalimportance: should knowfreq 30%

basics

~20 s

Column narrowing only happens automatically for derived query methods over a closed projection. A manual @Query (JPQL or native) selects exactly what you wrote, an @Value getter makes it open, or fetching the entity then mapping defeats it. To guarantee narrowing, use a closed projection on a derived method or explicitly select only the needed columns.

open as a page