Nextdoor Software Engineer Interview Questions & Guide 2026

Debugging practice for Nextdoor software engineer candidates: reproduce it, narrow it, then change one thing per run.

Topics: Nextdoor, Software Engineer, Interview Guide

Author: PracHub

Published: 9/10/2026

Nextdoor logo
Nextdoor · Software EngineerUpdated Sep 24, 2026 · Reviewed by PracHub

Nextdoor Software Engineer Interview Questions & Guide 2026

Debugging practice for Nextdoor software engineer candidates: reproduce it, narrow it, then change one thing per run.

Questions in our bank by interview round

  • HR Screen2 questions
  • Technical Screen11 questions

On this page0% read
01 · Overview

Interviewing at Nextdoor

As a Software Engineer at Nextdoor, you build technology that powers the essential neighborhood network. Nextdoor connects neighbors, local businesses, and public agencies across more than 350,000 neighborhoods worldwide in 11 countries. Your engineering efforts directly shape how hyper-local communities organize, communicate, discover local services, and support neighborhood economies. Nextdoor candidates report 3 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.

Practice bank
13+ questions
Round types in our bank
2
Interview reports
2
02 · Difficulty

How hard is the Nextdoor Software Engineer interview?

From 13 labelled questions
  • Easy0%0 questions
  • Medium77%10 questions
  • Hard23%3 questions

Most questions land in the middle: hard enough to prepare for, rarely brutal.

Read 2 Nextdoor interview reports from candidates who went through this loop.

03 · Topic breakdown

What Nextdoor actually tests for

Share of 13 Software Engineer questions
  1. System Design38% · 5
  2. Coding & Algorithms31% · 4
  3. Software Engineering Fundamentals15% · 2
  4. Behavioral & Leadership8% · 1
  5. Machine Learning8% · 1
04 · Question bank

The questions most likely to come up

13+ in the Nextdoor bank · sorted by popularity
  1. Design a Scalable Job SchedulerDesign a job scheduler for a small startup, then explain how you would evolve it to support roughly 100x more scheduled tasks.System DesignTechnical ScreenMedium
  2. Implement version string comparator with extensionsImplement a function compareVersions(a, b) that compares two software version strings. Each version consists of dot-separated numeric components…Coding & AlgorithmsTechnical ScreenCodingMedium
  3. Design In-Memory Transactions with Snapshots and SavepointsSoftware Engineering FundamentalsTechnical ScreenPremiumMedium
  4. Build and evaluate a Colab classification modelYou are asked to design and implement a complete classification workflow for a tabular dataset in Google Colab.Machine LearningTechnical ScreenHard
  5. Which culture principle resonates and whyAfter watching the company’s culture-fit video:Behavioral & LeadershipHR ScreenMedium
  6. Unlock every Nextdoor questionModel solutions on all of them, plus the coding and SQL consoles.See Premium
  7. Describe CAP, distributed systems, multithreading experienceProvide a structured answer that both explains the concepts and shows how you have applied them in real systems. Use concrete examples, trade-offs,…System DesignHR ScreenHard
  8. Merge Weekly Time IntervalsYou are given a list of time intervals within a single week. Each time is written as a day-of-week plus a 24-hour clock, for example Sat 13:00 or Mon…Coding & AlgorithmsTechnical ScreenCodingMedium
  9. File-System Tree from a Record Stream Where Children Can Arrive Before ParentsBuild an in-memory file system from a stream of input records. Each record describes one file or directory and names its parent, so together the…Software Engineering FundamentalsTechnical ScreenMedium
  10. Design a Job Scheduler That Can Scale by 100 TimesSystem DesignTechnical ScreenPremiumMedium
  11. Group Photos and Sort Feed ItemsCoding & AlgorithmsTechnical ScreenCodingPremiumMedium
  12. Design a Neighborhood Newsfeed SystemSystem DesignTechnical ScreenPremiumMedium
  13. Simulate Transaction Lock SchedulingCoding & AlgorithmsTechnical ScreenCodingPremiumHard
Practice 13+ Nextdoor questions

The 60-second brief

As a Software Engineer at Nextdoor, you build technology that powers the essential neighborhood network. Nextdoor connects neighbors, local businesses, and public agencies across more than 350,000 neighborhoods worldwide in 11 countries. Your engineering efforts directly shape how hyper-local communities organize, communicate, discover local services, and support neighborhood economies.

Nextdoor candidates report 3 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.

What a Software Engineer does at Nextdoor

In this role, you tackle high-scale engineering challenges that span real-time feed processing, complex data hierarchies, automated go-to-market (GTM) platforms, and high-throughput ad serving infrastructure. Nextdoor operates in an AI-first engineering environment, where software engineers leverage modern AI tools to accelerate development, improve systems architecture, and automate operational workflows. Whether you work on client platform engineering, backend infrastructure, or monetization tools, your code operates at massive scale where reliability and latency directly impact millions of daily active neighbors.

Working as a at demands a blend of algorithmic precision, practical architectural design, and product empathy. Engineers here are empowered to take end-to-end ownership of features—from technical specification and system modeling to deployment and monitoring—while collaborating closely with cross-functional partners in Product, Design, and Revenue Operations.

The Nextdoor interview process

Nextdoor candidates report 3 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.

Phone Screen

Before anything technical happens, someone has to decide which rung of the ladder your loop is calibrated to, and that decision sets the bar for every round after it. It comes from how you describe scope, not from your title, because titles do not convert cleanly between companies. The weak version of the answer is team size and years. The strong version names the largest change you shipped where nobody reviewed the design, what would have broken if you had been wrong, and what you were paged for. Get the level said out loud on this call, because the range and the loop both follow from it.

What it evaluates

  • Whether the scope in your own account maps onto a level the team actually has an opening at, so a mismatch ends the process cheaply rather than after four interviewers have spent a day
  • Whether your title needs re-mapping: the same word describes very different amounts of independent decision-making at a twenty-person company and a ten-thousand-person one
  • Whether your compensation expectation can be filled at that level in the structure the role pays in, which is why the number gets asked for before any engineer is scheduled

How to prepare

  • Write down two changes from the last two years: the largest one you designed with nobody reviewing the design, and the largest one where someone more senior did. Lead with the first when scope comes up, and be ready to say which parts of the second were yours
  • Ask which level the loop is calibrated to and what changes at the level above it, then plan your weeks from that answer rather than from the posting
  • Settle a total-compensation range beforehand with the split named, base against bonus against equity and its vesting period, so a question about numbers gets a number instead of the word market

Technical Interviews

The same problem is scored by two different mechanisms depending on the format, and preparing for one does not cover the other. With a person watching, partial progress is visible and a hint is a correction you can absorb; silence is the expensive failure, because nobody can read a half-written function. With an automated grader there is no partial credit for what you were about to do, nobody to ask, and the worked examples in the prompt are the entire specification. Read them as a contract, down to whether an empty result should be an empty list or no output at all.

What it evaluates

  • In a live session, whether your commentary tracks what your hands are doing, and whether a hint redirects you or gets defended against
  • In an automated one, whether you cover the cases the examples do not show, since the hidden cases are where the score moves
  • Whether you manage the clock on purpose: abandoning an approach that is not converging while there is still time to write something simpler that finishes

How to prepare

  • Have someone hand you a problem and feed you one deliberately wrong hint. Practise testing it against a concrete case instead of accepting or rejecting it on authority.
  • Do one timed run a week in a plain browser editor with autocomplete, linting and your own snippets switched off, which is closer to what these environments give you
  • For the automated format, write the harness before the solution: a main that feeds the worked examples plus an empty and a single-element case and prints expected against actual, so a wrong submission is caught by you first

Final Round

Coding rounds mostly set a floor. They decide whether you clear the bar, not where you land on the ladder. Level tends to come out of the design discussion and the ownership stories, so the question worth auditing beforehand is whether the scope you describe matches the scope of the job. Work that stops at your own service, or a story whose hard part was writing the code rather than getting several people to agree on an interface, reads a level below where you think you are interviewing, and that gap is usually resolved downwards.

What it evaluates

  • Whether the largest thing you describe owning ran end to end — the decision, the migration path, the rollout, and what you did when it went wrong — or stopped at the change you merged
  • Whether design answers include what you would not build, what you would defer, and what you would measure before committing, rather than only what the boxes are
  • Whether a disagreement in a story was settled with something checkable — a benchmark, a prototype, a written proposal — instead of by seniority or by waiting it out
  • Whether you can say which calls you made alone and which you escalated, and why the line sat where it did

How to prepare

  • Write your largest piece of owned work as a timeline of decisions — who decided what, when, and what you did when the plan broke — then delete every sentence whose subject is "we" and see how much survives
  • Take one system you know well and drill the migration answer: how old and new paths run side by side under live traffic, how you compare their outputs, what the rollback is once writes are going to both, and which step you would not automate
  • Map each line of the ladder in the job posting to a specific thing you have done, find the line you cannot support, and prepare the closest evidence you have plus an honest account of the gap

Questions Nextdoor candidates report

These are the prompts PracHub has collected for this role and company. They are a record of what candidates describe being asked, so treat them as the shape of the conversation rather than a script Nextdoor works from.

Data structures and algorithms

One structure rarely covers the whole operation set, and the interesting questions in this category are the ones where it does not. When you need constant-time lookup and constant-time reordering at once, or the minimum plus deletion of an arbitrary element, the answer is two structures that index each other: a map from key to the node holding it, beside the list or heap that maintains the order. What separates a strong answer is the invariant between them, stated explicitly. Every operation has to leave both halves consistent, and the bug people ship is a removal from one that leaves a stale entry in the other.

  • Implement a function to store post comments containing parent-child references, then traverse and display them in a hierarchical nested order using deep search techniques.
  • Solve a Secret Santa assignment problem starting with basic matching rules, then handle dynamic constraints introduced sequentially that introduce complex condition backtracking.
  • Traverse a hierarchical binary structure representing nested conversation threads and output a pre-order representation of the nodes.

System design and architecture

A design is a set of promises about what happens when something is slow, down, or delivered twice, and that is the part usually left unsaid. For each dependency, say what the system does when it is unavailable: serve stale data, reject the write, or accept it and settle later. For each relaxation of consistency, describe the anomaly a user would actually notice, in the product's own words, rather than naming a consistency model and moving on. The separator is volunteering the failure behaviour as part of the design instead of producing it only when pushed.

  • Design a scalable nested commenting infrastructure that supports fast lookups, soft deletions, and deep thread traversal for active local posts.
  • Architect a real-time notification service delivering localized safety alerts to millions of mobile devices simultaneously.

Behavioural and engineering judgement

Ownership questions here usually point at something with no owner and no deadline: an alert people mute, a suite everyone reruns until it passes, a service whose on-call is a rota of volunteers. Nothing forces action, so what you did says how you spend discretionary time. The strongest answers are not the ones where you fixed everything. They are the ones where you sized the problem first, chose between fixing it, containing it and writing it down for whoever comes next, told someone who could have overruled you, and can still say why the other two options were worse.

  • Walk me through a challenging technical project you led from inception to launch, focusing on the architectural hurdles you overcame.
  • Describe an instance where an unexpected production issue occurred and how you managed root-cause analysis and mitigation.

Other topics

Nothing constrains the range here, so expect at least one question at the edge of what you know. Answer at that edge deliberately: give the adjacent thing you do know, say plainly where your knowledge stops, and reason forward from the part you can defend. Calibration is itself information about you, and it is cheap to check, since one follow-up asking why will empty out an answer with nothing under it. Everything you have claimed as experience is fair material, so the item you last touched three years ago is worth an hour of re-reading rather than a hopeful skip.

  • Build a dynamic transaction manager implementing methods to begin transactions, acquire dynamic locks, execute deferred messages, and release locks safely upon task completion.

Practice exercises with worked solutions

The prompts above tell you what gets asked. These are PracHub exercises written to drill the same skills, with the reasoning spelled out so you can check your own answer instead of guessing whether it was good enough.

Page a feed with a cursor that survives head inserts

timeline_entry holds owner_id, content_id, author_id, inserted_at_utc, sort_key, source, with PRIMARY KEY (owner_id, content_id). New entries arrive at the head between a viewer's requests. Write the query for page one and the query for page n returning 30 entries newest first with no duplicate and no skip, give the index that makes it a seek rather than a sort, and state what the cursor must contain if sort_key is not unique within an owner. Then say what your loop does when the visibility filter removes every row on a page.

How a strong candidate works it

  • Reject OFFSET on two grounds rather than one. It defines the window by counting from a start that moves, so k head inserts repeat k rows and deletions skip the same number with no signal; and the database must produce and discard OFFSET rows before returning any, so page n costs O(offset + limit) and deep pages degrade even where the correctness problem is invisible.
  • Page one: SELECT content_id, author_id, sort_key FROM timeline_entry WHERE owner_id = $1 ORDER BY sort_key DESC LIMIT 30. Page n seeks: the same with AND sort_key < $2, where $2 is the last row's sort_key. Keep them as two statement shapes rather than one with ($2 IS NULL OR sort_key < $2), whose OR is not an index bound in a generic plan.
  • Index (owner_id, sort_key). Be precise about direction: a single-key ordering is served by a backward scan of an ascending B-tree, so DESC in the index definition buys nothing here and only matters when the ordering mixes directions across columns.
  • If sort_key can repeat within an owner the scalar cursor is ambiguous at the boundary and the tied rows are either repeated or dropped. Make the cursor a pair and compare as a row value, (sort_key, content_id) < ($2, $3), with index (owner_id, sort_key DESC, content_id DESC) so the planner turns it into one index bound. This is why the sort key is a time-sortable id and not a timestamp.
  • Handle the hybrid page: items from pull-mode authors are not in this table, so apply the same cursor predicate to content_item for those authors, merge on the same key, dedupe on content_id, and only then cut to 30 - cutting before merging loses items that belong on the page.
  • Advance the cursor by the last row examined, not the last row returned. If a page filters to nothing and you carry forward the last returned row, the cursor never moves and the client loops forever; over-fetch (45 for a page of 30) to keep the round trips down.

Follow-ups

  • The viewer scrolls past the timeline's 800-entry cap. What does the next page return, and where do those items come from?
  • Ranking reorders the page by score instead of recency. Is the cursor still valid, and what would replace it?
  • Show the EXPLAIN difference between the seek form and the OFFSET form at page 200.

Stop the engagement join from multiplying feed counts

A feed page hydrates 50 content_ids. Someone joins content_item to engagement (actor_id, content_id, action_kind, undone_at_utc) and to media_rendition (asset_id, rendition_profile, state) in one statement to return, per item, the live like count, the live save count, whether this viewer liked it, and the number of ready renditions. Likes and saves come back inflated, and items with no renditions disappear from the result. Explain the row arithmetic behind both symptoms, write the corrected query, and say which parts of it should not run on the feed hot path at all.

How a strong candidate works it

  • Name the arithmetic: joining one parent to two independent child tables produces their cross product per parent. An item with 460 engagement rows and 3 renditions yields 1,380 rows, so like_count comes back as 400 x 3 = 1,200 and ready_renditions as 3 x 460 = 1,380 - each side inflated by exactly the other side's cardinality. The error scales with popularity, so a fixture with one rendition and two likes shows nothing.
  • The vanishing items are a separate bug with a wider blast radius than the prompt's wording suggests. Writing undone_at_utc IS NULL and state = 'ready' in the outer WHERE turns both LEFT JOINs into inner joins, because a NULL produced by a non-matching row fails the predicate. state = 'ready' alone drops every item that has no ready rendition, which includes all text-only items, not just the item nobody has engaged with. Filters on the nullable side belong in the ON clause or inside the aggregate.
  • Fix the grain rather than the symptom: aggregate each child at its own grain before joining, one LEFT JOIN LATERAL per child returning exactly one row, so the outer query stays at one row per content item. COUNT(DISTINCT actor_id) FILTER (...) also returns the right number but pays a sort or hash per group and cannot rescue a SUM, so it is a patch and not the model.
  • Make the viewer flag a batched lookup on (actor_id, content_id) over the 50 ids rather than a correlated existence test per item; the per-item pattern is the one that passes review because each individual query is fast, and it is caught by counting the lookups one page issues.
  • Then say what does not belong on this path: counting engagement rows per item on every render is precisely the work the denormalised counter exists to avoid. The hot path reads the counter, which is approximate between reconciliations, and this query is the reconciliation job. Rendition readiness is a state the item should carry, not a COUNT computed per request.

Expected result (25 min): The naive join returns 1,380 rows and only for the first item, reporting like_count 1,200 and save_count 180. The second item has likes but no rendition, so state = 'ready' drops it, and the third matches neither predicate, so both drop it - one item survives out of three, and the inflation and the disappearances are the same predicate-placement mistake rather than two bugs. The LATERAL version returns exactly three rows - (400, 60, 3), (12, 0, 0) and (0, 0, 0) - each with the viewer flag, including the item nobody has touched.

Check yourself

  • like_count matches SELECT count(*) FROM engagement WHERE content_id = $1 AND action_kind = 'like' AND undone_at_utc IS NULL run on its own.
  • The number of rows returned always equals the number of ids passed in - that is the grain test, and the naive query fails it in both directions at once, too many rows for the first item and no rows for the other two.
  • Deleting the item's renditions changes ready_renditions and leaves like_count untouched.

Follow-ups

  • Add the top three commenters per item to the same result. What changes, and where does the fan-out come back?
  • The reconciliation job runs this across 400 million items. How do you batch it, and what index does each batch need?
  • The viewer flag for 50 items should be one lookup. What is the key, and what does the index look like?

Merge pushed and pulled timelines into one deduplicated page

A feed page must combine one materialized timeline, a list of (content_id, author_id, sort_key) sorted by sort_key descending, with the recent-item lists of up to 300 pull-mode authors the viewer follows, each also sorted descending and up to 500 items long. Return the top 50 by sort_key with no content_id repeated, since an author whose fanout_mode flipped can appear in both sources. You may not materialize the concatenation. Give the algorithm, its complexity in the number of lists and the page size, the memory it holds, and the cursor you hand back.

How a strong candidate works it

  • Run an L-way merge over one cursor per list rather than a global sort. Seed a max-heap with each list's head, which is O(L) to heapify, then pop and advance until 50 items have been emitted: O(L + (P + d) log L) where P is 50 and d is the number of duplicates skipped. Memory is O(L) for the heap plus O(P) for the emitted set.
  • Price the alternative so the choice is visible: concatenating and sorting is O(N log N) over up to 150,000 rows to return 50, and it holds all of them. The merge touches L + P + d elements. That is the entire argument, and it is quantitative rather than stylistic.
  • Apply the dedup at pop time, before the item consumes one of the 50 slots. Keep a hash set of emitted content_ids; on a pop that is already present, advance that list and continue without emitting. Termination is guaranteed because every iteration consumes exactly one element from some list.
  • Make the comparator total. If sort_key is the time-sortable content_id, keys are globally unique and ties cannot occur, so say that; if sort_key is ever a timestamp, two lists can present equal keys, and without content_id as an explicit tiebreaker the same request returns two different orders on two runs, which makes the cursor ambiguous rather than merely untidy.
  • Return a cursor of (sort_key, content_id) from the last emitted row, and on the next page binary-search each list for the first element strictly below it, O(log 500) per list. Restarting the merge from every list's head instead re-reads and re-discards the whole prefix, which turns page n into O(n) work.

Expected result (25 min): A 50-item page from an L-way heap merge over one cursor per list: O(L + (P + d) log L) time, O(L + P) space, dedup applied before a slot is consumed, a total comparator, and a (sort_key, content_id) cursor that the next page seeks to in O(log 500) per list.

Check yourself

  • Placing the same content_id at the head of the timeline and of one pull list yields one copy and still 50 items.
  • Setting every list's head to the same sort_key produces the same emitted order on two runs of identical input.
  • Counting element reads gives L seeks plus at most P + d advances, not 150,000.
  • Paging twice with the returned cursor produces no item that appeared on page one and skips nothing between the two pages for a static input.

Follow-ups

  • The viewer follows 3,000 pull-mode authors rather than 300. Where does this design break first, and what do you change?
  • One pull list's backing store times out. What do you return to the caller, and what does the cursor mean afterwards?
  • An author flipped from push to pull halfway through the time range this page covers, so some of their items are materialized and some are not. Walk through why the merge still covers the gap, and name the implementation choice that would open a hole.

Define an error taxonomy a retrying client can act on

Read and write endpoints currently return a bare HTTP status and a human-readable string. Callers are the first-party mobile app and third-party integrators, both of which retry automatically. Design the error contract: the fields in the body, how a stable machine-readable code relates to the HTTP status, and which classes a caller may retry. Cover at least invalid payload, unauthenticated, not visible to this viewer, quota exceeded, conflicting state, and an upstream timeout on a write. For each class state what the caller does next, including the case where a write's outcome is unknown.

How a strong candidate works it

  • Separate three axes that are usually conflated: the HTTP status, which intermediaries and generic retry middleware act on; a stable machine code the client switches on; and a human message the client must never parse. RFC 9457 problem+json (which obsoletes RFC 7807) gives type, title, status, detail and instance, and the stable code belongs in an extension member, not in title.
  • Map each class to a status deliberately. Invalid payload is 400 for malformed and 422 for well-formed but semantically wrong; unauthenticated is 401 and authorization-by-visibility is 404, not 403, because a 403 on a blocked author's item confirms that the item exists and turns the error into an existence oracle.
  • Publish retryability in the body (retryable true/false, plus retry_after_ms where the server knows) instead of making every client re-derive it from the status. 429, 502, 503, 504 and connection failures are retryable; 400, 401, 403, 404, 409 and 422 are terminal and retrying them only burns quota.
  • Treat an indeterminate write as its own class: a timeout or 5xx on an unsafe method means the write may have committed. The contract's answer is to require an idempotency key or an idempotent method on every unsafe endpoint, so 'resend the identical request' is always safe; otherwise the only correct client action is to re-read state.
  • Put the retry policy in the contract rather than in each client: exponential backoff with full jitter, a bounded attempt count, honouring Retry-After, and a circuit breaker. State that ignoring Retry-After escalates to a longer block, so the polite path is also the fast path.

Expected result (20 min): A problem+json body carrying a stable code plus a retryable flag; visibility failures returning the same 404 as a nonexistent id; 429 and 5xx marked retryable with backoff plus jitter and a bounded attempt count; and an explicit rule that a timed-out write is unknown, resolved by resending an idempotent request or re-reading, never by a blind resend of a non-idempotent one.

Check yourself

  • Every class in the table has exactly one caller action, with no 'it depends'.
  • No two distinct failure causes share one code.
  • A client that knows only the code and the retryable flag, and never reads the message, can still behave correctly.
  • Requesting a blocked author's item and requesting a nonexistent id produce identical responses.

Follow-ups

  • How do you add a new error code later without breaking clients that switch exhaustively on the code?
  • One request publishes an item but fails to enqueue its notifications — which status and which body?
  • Which of these should page an on-call engineer, and which are normal traffic?

Feed pods reach their memory limit once daily restarts stop

Feed service pods grow from 1.2 GB resident after start to the 6 GB limit in about nine hours, then get OOM-killed. This began when daily deploys stopped for a code freeze; nothing else changed. Growth tracks distinct viewers served rather than request count. Heap profiles taken two hours apart show retained growth concentrated in one process-global map holding each viewer's blocked-account set, populated on first read and never removed. Give the ordered checklist, both defects you expect to find, and the fix with its stated bounds.

How a strong candidate works it

  • Name the growth precisely, because the name determines the fix. Nothing here is unreachable, so this is not a leak in the garbage-collected sense; it is an unbounded cache, and a heap profiler will show it as live retained memory rather than as garbage. Diff two profiles by retained size, not by allocation rate, since an allocation-rate view is dominated by short-lived request objects and will point at the wrong site.
  • Use the correlation as the discriminator. Growth proportional to distinct viewers rather than to request count means one entry per identity, which is the signature of a per-identity map with no eviction. Growth proportional to request count would instead suggest an accumulating buffer or an unclosed resource, and the two have nothing in common as fixes.
  • Explain why it surfaced now rather than treating the code freeze as a coincidence. Daily deploys were restarting processes before they could reach the limit, so the pods were being silently reset every day. The freeze did not create the defect; it removed the thing that was hiding it.
  • Find the second defect by asking what invalidates the map, because a cache with no eviction usually has no invalidation either. Nothing here removes an entry, so a viewer who blocks an account keeps seeing that account's items on any process that already cached the old set, until that process restarts. That is a correctness failure against the block invariant, and the daily restarts were masking it too, which is why no one reported it while deploys were frequent.
  • Fix both with one structure and commit to numbers. Replace the map with a bounded LRU carrying an explicit per-entry TTL: a 50,000-entry cap at roughly 2 KB per entry bounds the cache near 100 MB, and a 60 second TTL bounds staleness at 60 seconds plus request duration. State the trade openly: a newly created block can take up to a minute to take effect on already-warm processes, and that bound is the guarantee.
  • Add invalidation on block creation as an optimisation on top, not as the guarantee. Publishing an invalidation to subscribing processes usually reduces staleness to under a second, but delivery is best-effort and a process that missed the message must still converge, which is precisely what the TTL provides. A design that relies on the notification alone has an unbounded staleness window whenever the notification is lost.

Follow-ups

  • Sizing the cap requires an entry size. How do you measure the real retained size of one viewer's blocked set rather than estimating it?
  • A viewer who follows thousands of accounts and blocks thousands more has an unusually large entry. What does that do to a cap expressed in entries, and would you cap bytes instead?
  • With a 60 second TTL, what do you tell a user who blocks someone and immediately reloads their feed, and what would it cost to make that case exact?

Own the outage where one fanout starved every other author

Every author's timeline writes share one fanout queue. A publish by an account with roughly 12 million followers enqueued its entire follower fan, and for 41 minutes items from ordinary authors stopped reaching feeds while the backlog drained. Nothing errored: publishes returned 200, the read path was healthy, and error-rate dashboards stayed flat. Take the on-call role. Describe an incident you owned with a comparable silent blast radius: how it was detected, how you bounded who was affected, what you stopped first, and the one metric that sized the damage. Include what you got wrong during the response.

How a strong candidate works it

  • Open with the invariant that broke, stated in a measurable form: a published item is materialized into follower timelines within N seconds at p99. The symptom (feeds look stale) tells a listener nothing countable; the invariant names both the damage and the metric.
  • Explain why nothing errored, because that is the interesting part. An at-least-once queue degrades by lag, not by failure, so the detector has to be the age of the oldest unprocessed publish event per partition. Queue depth alone hides this case: depth is small when one task is enormous.
  • Bound the population with two numbers you can derive, not an adjective. Publishes enqueued behind the stalled fan is a count from the queue; readers affected is the sum of account.follower_count over those authors. Say which one you actually computed during the incident and which you reconstructed after.
  • Separate mitigation from fix and say which came first. Mitigation is to stop paying the cost now: flip the offending author to pull mode or move that fan to an isolated partition so small fanouts drain. State its immediate cost, which is a read path that must merge pushed and pulled items mid-incident. The threshold and per-size partitioning are the fix and are not an incident-window change.
  • Say what redelivery did while you drained. Because a timeline write is an upsert on (owner_id, content_id), replayed events rewrote the same slots and the recovery was re-runnable; if the write had been an append, draining would have doubled entries in every timeline it touched.
  • Name one thing you got wrong inside the response window, such as a mitigation that made the backlog worse or time spent on the wrong hypothesis. Interviewers weight this heavily because it is the part candidates rehearse away.

Follow-ups

  • Your mitigation flipped one author to pull mode. What must the feed read path do differently for viewers who follow that author, and how do you avoid serving them the item twice while already-pushed rows still exist?
  • How would you have detected this in five minutes instead of 41, and what would that detector cost in false pages per week?
  • The queue drained but some viewers were still missing items. Where do you look, and what exactly do you rebuild?

Where candidates lose points

Maintaining derived state from an at-least-once stream without a dedup key

Queue and log consumers redeliver on rebalance, on timeout and on any failure between processing and offset commit, so every handler runs more than once eventually — under normal operation, not just in incidents. A handler that appends a timeline row or increments a counter produces duplicates that no later retry can undo, and because redelivery is triggered by load, the corruption clusters exactly when traffic is highest. The property to design for is idempotency of the apply, not exactly-once delivery, which the transport does not provide: make the timeline write an upsert on (owner_id, content_id), and make counter updates conditional on a dedup record or reconcile them from the source table. Ordering has the same shape — a partitioned log guarantees order only within a partition, so an edit and its delete stay ordered only if both are keyed to the same partition.

Maintaining a popular count as a single mutable row

Concurrent writers to one row serialize on that row's lock, so throughput is bounded by one transaction's duration regardless of how many application servers are running. In PostgreSQL under READ COMMITTED an UPDATE that reads the column it writes is safe from lost updates — the blocked writer re-evaluates the row after acquiring the lock — so the failure is throughput and lock-wait latency, not a wrong number; under REPEATABLE READ the same statement instead aborts with a serialization failure, which surfaces as a burst of retried writes on exactly the hottest item. Either way the row becomes a convoy point under viral traffic. The fixes are to shard the counter into N sub-rows keyed by a random or hashed suffix and sum on read, trading read cost for write concurrency, or to move increments into an append-only log reconciled on a schedule — which is only acceptable if the count is explicitly allowed to be approximate between reconciliations.

Answering a debugging question with a guess instead of a bisection

Give a procedure that halves the search space at each step: confirm the symptom reproduces, establish the last known-good version, input or timestamp, then bisect over commits, over the data, or over the layers of the request path. A plausible cause with no way to confirm it is the same move whether it happens to be right or wrong, which is why it scores nothing.

Going silent while thinking

Narrate the candidates and why you are discarding them, even in fragments: sorting first would make this a two-pointer scan, but it destroys the original indices, which the output needs. From the other side of the table, a candidate thinking hard and a candidate stuck are indistinguishable until one of them speaks.

Weakness triage, driven by a day-one self-assessment

Day one measures instead of guessing, under a fixed rubric, and the remaining hours are allocated in proportion to the gaps before any studying begins. The allocation is deliberately not renegotiated midweek, because the area that feels worst on day three is usually the one that is moving.

Day 1 — Diagnostic, scored before you study anything

  • Sit a 110-minute diagnostic in four blocks: forty-five minutes on two coding problems, twenty-five on one design prompt taken to interface and data model, twenty of short-answer fundamentals, and twenty delivering two behavioural answers aloud.
  • Score each block from 0 to 3 on a fixed rubric where 3 is correct and fluent, 2 is correct but slow or prompted, 1 is partially correct and 0 is stuck, grading the artifact rather than how the attempt felt.
  • Allocate days two to five in proportion to 3 minus each block's score, write the allocation down, and commit to leaving it alone.

Deliverable: A scored rubric and a fixed hour allocation for the rest of the week.

Day 2 — Largest gap: find the boundary rather than the subject

  • Split the weakest area into named sub-skills and rate each separately. For coding those are restating the problem, choosing the structure, stating the invariant, turning the invariant into loop bounds, handling empty and single-element input, and accounting for complexity out loud.
  • Attempt three items positioned just above where the rating drops off, and for each write the first move you failed to make.
  • Re-attempt one of them from blank four hours later with nothing open.

Deliverable: A sub-skill map with the two blocking sub-skills circled.

Day 3 — Drill the blocking sub-skill by repeating the shape

  • Do eight short repetitions of the same shape rather than eight different problems, so what gets practised is the pattern and not the puzzle.
  • State the rule you now hold in one sentence, then test it against a case built to break it, a sliding window over an array containing negative values, or a cache-aside read path whose invalidation message is dropped.
  • Have someone else read your one-sentence rule and find the precondition you left out.

Deliverable: One rule statement with its preconditions attached and one counterexample that would have caught the incomplete version.

Day 4 — Second gap, plus maintenance on the strongest area

  • Run the same sub-skill decomposition on the second-largest gap in half the time.
  • Spend twenty-five timed minutes on the block you scored highest, choosing the hardest item you can still finish rather than a warm-up.
  • Write whether each area fails you on recall, on setup, or on execution, and set the fix accordingly: repetition for recall, a written checklist for setup, timed work for execution.

Deliverable: A second sub-skill map plus a one-line failure diagnosis for each area.

Day 5 — The gap that is not a skill

  • Record one technical and one behavioural answer, then count two things in the playback: seconds before your first clarifying question, and sentences you began without knowing where they would end.
  • Practise saying that you do not know, followed by how you would find out, without letting it soften into a guess, and practise stating a complexity or an estimate before being asked for it.
  • Redeliver one answer under a hard ninety-second cap, which forces structure ahead of detail.

Deliverable: Two recordings with a counted reduction in time-to-first-question.

Day 6 — Retest under day-one conditions

  • Sit the same 110-minute structure with new prompts of comparable difficulty and score it on the identical rubric.
  • For any block that did not move, change the method rather than adding hours: a block stuck at 1 usually means the practice was too varied, not too short.
  • Write down which single block you would still lose the offer on.

Deliverable: A second scored rubric placed beside the first, with one named remaining risk.

Day 7 — Full loop under interview conditions

  • Run a sixty-minute mock over the two blocks that moved least, with an interviewer briefed to interrupt and change direction mid-answer.
  • Write the recovery script for going blank: restate the question, state your assumption, name the first thing you would check.
  • Say every rule from the week aloud without reading it, and cut any you cannot state in a single sentence, since a rule you have to reconstruct mid-answer will not survive an interruption.

Deliverable: A one-page card holding the recovery script and only the rules you could state from memory.

Frequently asked questions

Is this an official Nextdoor interview guide?

No. It is PracHub's own research and practice material for the Software Engineer role at Nextdoor. Rounds and questions reflect what candidates have reported, not a process Nextdoor has published, and they change over time. Confirm the current format and scope with your recruiter.

How difficult are the technical interviews at Nextdoor?

The technical difficulty is average to challenging, with questions typically mirroring medium-level algorithmic problems focusing on tree/graph traversals, state machine simulations, and nested data structures. System design rounds focus heavily on real-world local social networks and ad infrastructure problems.

Does Nextdoor allow me to choose my preferred programming language for coding rounds?

Yes, you can generally choose any major modern language (such as Python, Java, C++, Go, or JavaScript/TypeScript) during coding interviews. Python is widely used internally and recommended for rapid prototyping during short coding windows.

How does Nextdoor incorporate AI tools into the engineering culture?

Nextdoor embraces an AI-first operating model. Engineers are encouraged and expected to actively use modern AI tools to augment their thinking, write test suites, speed up debugging, and refine system documentation.

What sets successful candidates apart during the interview process?

Successful candidates articulate their thought process clearly before writing code, write unit test cases manually to verify their logic, respond constructively to interviewer hints, and demonstrate genuine interest in Nextdoor's community mission.

Keep practising

More questions candidates ask

No. It is PracHub's own research and practice material for the Software Engineer role at Nextdoor. Rounds and questions reflect what candidates have reported, not a process Nextdoor has published, and they change over time. Confirm the current format and scope with your recruiter.

The technical difficulty is average to challenging, with questions typically mirroring medium-level algorithmic problems focusing on tree/graph traversals, state machine simulations, and nested data structures. System design rounds focus heavily on real-world local social networks and ad infrastructure problems.

Yes, you can generally choose any major modern language (such as Python, Java, C++, Go, or JavaScript/TypeScript) during coding interviews. Python is widely used internally and recommended for rapid prototyping during short coding windows.

Nextdoor embraces an AI-first operating model. Engineers are encouraged and expected to actively use modern AI tools to augment their thinking, write test suites, speed up debugging, and refine system documentation.

Successful candidates articulate their thought process clearly before writing code, write unit test cases manually to verify their logic, respond constructively to interviewer hints, and demonstrate genuine interest in Nextdoor's community mission.

NextdoorSoftware EngineerInterview Guide