← Back to Practice
Practice · Interview · Card 1
includes vs preload vs eager_load vs joins
A classic Rails interview question. The interviewer wants four distinct behaviors named precisely, plus when you'd pick each.
The question
"Explain the difference betweenincludes,preload,eager_load, andjoins. When would you pick each one?"
Your job
Form an answer that names all four behaviors precisely and gives one clear pick for each. Don't reach for the docs.
Take a moment. Two of these issue two queries, two issue one. Two load the association, two only filter by it. Sort them out.
The senior framing
preload— two queries, no SQL join. One for the parent, oneIN(...)for the children.eager_load— one query with a LEFT OUTER JOIN, all data in one result set.includes— Rails picks between preload and eager_load based on whether you reference the joined table in a WHERE.joins— INNER JOIN, used for filtering by the joined table. Does not load the associated records.
Pick by use case:
includesas the default — let Rails decide.preloadwhen you specifically want two queries (avoids a giant JOIN result set with N×M rows).eager_loadwhen you need to filter on the joined table's columns.joinswhen you only need to filter, not access. Often.joins(:user).where(users: { admin: true }).
Junior framings that don't land
- "They're all aliases of each other." They're not. They generate different SQL and behave differently when you add WHERE clauses on joined tables.
- "They all issue one query; they just differ in syntax."
preloadalways issues two (or more for nested associations). - "
joinsis the same aseager_load." The most common confusion.joinsdoesn't load the rows intopost.user, so accessing the association after still N+1s. - "I just always use
includesand trust Rails." A common answer that works often but signals you haven't dissected why. Senior includes the "and here's when I'd switch."
The trap to avoid
joins + accessing the association is the most common silent N+1 in Rails code. Post.joins(:user).each { |p| p.user.name } does the JOIN to filter, then N more SELECTs for each user. Use includes or eager_load when you'll touch the joined record.
Theory
Full walkthrough at Eager Loading — includes vs preload vs eager_load vs joins.