Nextdoor

Nextdoor Software Engineer Phone Screen Questions

15+ questions from real Nextdoor Software Engineer Phone Screen rounds, reported by candidates who interviewed there.

15
Questions
7
Topic Areas
10+
Sources

What does the Nextdoor Phone Screen round test?

The Nextdoor phone screen typically lasts 45-60 minutes and evaluates core Software Engineer fundamentals. Candidates should expect 1-2 algorithmic problems, basic system design discussion at senior levels, and questions about relevant experience. The goal is to confirm technical competence before bringing candidates onsite.

Top Topics in This Round

Nextdoor Software Engineer Phone Screen Questions

The niche Nextdoor Coding: Print comments Merge interval with start and end time in format like Monday 12:30, Tuesday 17:20 Design: Design a jenkins like job scheduling system

## Problem Given a flat list of comment objects (each with an id and optional parent_id), reconstruct the nested tree structure and implement depth-first traversal for rendering. ```python from dataclasses import dataclass, field from typing import Optional @dataclass class Comment: id: int author: str body: str parent_id: Optional[int] children: list['Comment'] = field(default_factory=list) def build_tree(comments: list[Comment]) -> list[Comment]: # Returns list of root-level comments with children populated pass def render_thread(roots: list[Comment], indent: int = 0) -> str: pass ``` **Example:** ``` comments = [ Comment(1, "alice", "First!", None), Comment(2, "bob", "Reply to first", 1), Comment(3, "carol", "Reply to bob", 2), ] build_tree(comments) -> [Comment(1, children=[Comment(2, children=[Comment(3)])])] ``` ## Follow-ups 1. What data structure makes `build_tree` run in O(n) rather than O(n^2)? 2. How would you handle orphaned comments (parent_id points to a non-existent comment)? 3. How would you sort children by score (upvotes - downvotes) at each level? 4. How would you implement lazy loading so deep sub-threads are only fetched on expand?

## Problem Compute the sum of all integers in a nested list weighted by their depth. ## Likely LeetCode equivalent LC 339 (Nested List Weight Sum) is the direct match. ## Tags binary_tree, recursion, DFS

## Problem On a mobile client, URLs often contain sensitive data in query parameters (auth tokens, user IDs, emails). Write a function that strips or masks a configurable set of parameter names before the URL is written to logs. ```kotlin // Android (Kotlin) fun desensitizeUrl( url: String, sensitiveKeys: Set<String> = setOf("token", "email", "uid", "password"), mask: String = "***" ): String ``` **Example:** ``` desensitizeUrl("https://api.example.com/user?uid=42&token=abc123&page=2") -> "https://api.example.com/user?uid=***&token=***&page=2" desensitizeUrl("https://example.com/no-params") -> "https://example.com/no-params" ``` ## Follow-ups 1. How do you handle URL-encoded parameter values (e.g., `email=user%40example.com`)? 2. What edge cases arise with repeated parameters (e.g., `tag=a&tag=b&token=x`)? 3. How would you extend this to mask sensitive path segments (e.g., `/users/{uid}/profile`)? 4. Should you mask or omit sensitive parameters entirely? What are the trade-offs for debugging?

## Problem In an Android-style view system, each view has an integer ID. Views can be nested in ViewGroups. Implement `findViewByIdRecursive` that searches the view tree and returns the first view matching the given ID. ```java public abstract class View { private int id; public int getId() { return id; } public View(int id) { this.id = id; } } public class ViewGroup extends View { private List<View> children = new ArrayList<>(); public void addChild(View v) { children.add(v); } public List<View> getChildren() { return children; } public ViewGroup(int id) { super(id); } } public static View findViewByIdRecursive(View root, int targetId) { ... } ``` **Example:** ``` ViewGroup root(0) -> [View(1), ViewGroup(2) -> [View(3), View(4)]] findViewByIdRecursive(root, 3) -> View(3) findViewByIdRecursive(root, 99) -> null ``` ## Follow-ups 1. DFS or BFS — which is better here, and does it matter for correctness? 2. How would you optimize repeated lookups by caching ID-to-view mappings? 3. How would you handle the case where duplicate IDs exist in the hierarchy? 4. How would you add `findAllViewsById` that returns all matching views?

## Problem Given two hashmaps (dicts) A and B, compute their difference report: keys only in A, keys only in B, keys in both but with different values, and keys in both with identical values. ```python from dataclasses import dataclass from typing import Any @dataclass class DiffReport: only_in_a: dict # key -> A[key] only_in_b: dict # key -> B[key] changed: dict # key -> (A[key], B[key]) unchanged: dict # key -> value def dict_diff(a: dict, b: dict) -> DiffReport: pass ``` **Example:** ``` a = {"x": 1, "y": 2, "z": 3} b = {"y": 99, "z": 3, "w": 4} dict_diff(a, b) -> DiffReport( only_in_a={"x": 1}, only_in_b={"w": 4}, changed={"y": (2, 99)}, unchanged={"z": 3} ) ``` ## Follow-ups 1. How do you handle nested dicts — would you diff recursively? 2. What equality check do you use for values that may be lists or objects? 3. How would you serialize the DiffReport as a human-readable patch format? 4. How would you apply a DiffReport to transform dict A into dict B?

## Problem A home feed can have thousands of posts. Rendering all DOM nodes at once causes severe performance problems. Implement a virtualized list that only renders the posts currently visible in the viewport, plus a small buffer above and below. ```js class VirtualizedFeed { constructor(container, items, itemHeight) { // container: HTMLElement // items: array of data objects // itemHeight: fixed height per item in px } render() { ... } // initial render onScroll() { ... } // called on scroll event; updates visible window updateItems(newItems) { ... } // append or prepend new items } ``` **Requirements:** Only N visible items + 5 buffer items above and below are in the DOM at any time. Scroll position must feel native. ## Follow-ups 1. How do you calculate which item indices are visible given scrollTop and containerHeight? 2. How do you maintain scroll position when prepending new items (e.g., "5 new posts") at the top? 3. How do variable-height items change the virtualization math? 4. How would you handle keyboard navigation (arrow keys) through the virtualized list?

## Problem Given a list of integers and K, partition it into exactly K non-empty contiguous subarrays. Minimize the difference between the maximum subarray sum and the minimum subarray sum across all K groups. ```python def split_integers(nums: list[int], k: int) -> tuple[list[list[int]], int]: # returns: (partition, max_sum - min_sum) pass def min_split_difference(nums: list[int], k: int) -> int: # returns: the minimum achievable difference pass ``` **Example:** ``` nums = [1, 2, 3, 4, 5], k = 2 # Best split: [1,2,3] sum=6, [4,5] sum=9 -> diff=3 # Or [1,2,3,4] sum=10, [5] sum=5 -> diff=5 min_split_difference([1,2,3,4,5], 2) -> 3 ``` ## Follow-ups 1. How does a DP formulation with states (index, groups_remaining) solve this? 2. What is the time complexity of your DP solution? 3. How would binary search on the answer simplify the problem (binary search on difference)? 4. Does the order of elements in the array matter? What if elements can be rearranged?

## Problem Implement bidirectional conversion between nested JSON and a flat dot-notation key-value format. Nested keys are joined with `.`; array indices use bracket notation. ```python def flatten_json(obj: dict, prefix: str = "") -> dict[str, str]: # {"a": {"b": 1}, "c": [2, 3]} -> {"a.b": "1", "c[0]": "2", "c[1]": "3"} pass def unflatten_json(flat: dict[str, str]) -> dict: # Reverse of flatten_json pass ``` **Example:** ``` flatten_json({"user": {"name": "Alice", "scores": [10, 20]}}) -> {"user.name": "Alice", "user.scores[0]": "10", "user.scores[1]": "20"} unflatten_json({"user.name": "Alice", "user.scores[0]": "10", "user.scores[1]": "20"}) -> {"user": {"name": "Alice", "scores": [10, 20]}} ``` ## Follow-ups 1. How do you handle key collisions when a path could be both a leaf and a subtree? 2. How do you distinguish between a string value "10" and an integer 10 in the flat format? 3. How would you extend this to support mixed arrays (arrays containing both objects and primitives)? 4. What is the maximum nesting depth your solution supports before hitting Python's recursion limit?

## Problem Find the maximum area of an island (connected group of 1s) in a binary grid. ## Likely LeetCode equivalent LC 695 (Max Area of Island) is the direct match. ## Tags graph, DFS, matrix

## Problem Compute the sum of elements within a given range, possibly using a prefix sum array for efficient queries. ## Likely LeetCode equivalent LC 303 (Range Sum Query - Immutable) is the direct match. ## Tags arrays, prefix-sum

## Problem Given a list of participants and an exclusion list (pairs who should not be matched, e.g., couples or family members), generate a valid Secret Santa assignment where every person gives to exactly one other person, receives from exactly one person, and no exclusion is violated. ```python from typing import Optional def secret_santa( participants: list[str], exclusions: list[tuple[str, str]] # (a, b) means a must not give to b ) -> Optional[dict[str, str]]: # {giver: receiver} or None if impossible pass ``` **Example:** ``` participants = ["Alice", "Bob", "Carol", "Dave"] exclusions = [("Alice", "Bob"), ("Bob", "Alice")] # couple secret_santa(participants, exclusions) # Valid: {"Alice": "Carol", "Bob": "Dave", "Carol": "Bob", "Dave": "Alice"} ``` ## Follow-ups 1. How do you model this as a graph problem (directed Hamilton cycle with forbidden edges)? 2. When is a valid assignment impossible? Give a minimal example. 3. How would you ensure the assignment is uniformly random among all valid assignments? 4. How would you scale this to 500 participants with complex exclusion rules?

## Problem Sort or compare a list of semantic version strings (major.minor.patch) in the correct order. ## Likely LeetCode equivalent LC 165 (Compare Version Numbers) is closely related. ## Tags strings, sorting

## Problem Build a feed list component that loads items in pages from a paginated API. As the user scrolls near the bottom, the next page is automatically fetched and appended. Items already fetched should not be re-fetched. ```ts interface FeedItem { id: string; content: string; } interface FeedPage { items: FeedItem[]; nextCursor: string | null; } async function fetchPage(cursor: string | null): Promise<FeedPage> { ... } class FeedList { private items: FeedItem[] = []; private cursor: string | null = null; private loading = false; async loadMore(): Promise<void> { ... } // fetch next page onScroll(scrollTop: number, clientHeight: number, scrollHeight: number): void { ... } render(): FeedItem[] { return this.items; } } ``` **Requirement:** Prefetch the next page when the user is within 20% of the bottom. ## Follow-ups 1. How do you prevent multiple simultaneous fetches if the user scrolls rapidly? 2. How would you handle a fetch error mid-scroll gracefully (retry strategy)? 3. If items can be deleted from the feed server-side, how do you handle stale cursors? 4. How would you implement pull-to-refresh that resets the feed from the top?

## Problem Build the core logic and frontend for a card-matching memory game. An NxM grid of face-down cards hides N*M/2 pairs. Players flip two cards per turn; a match keeps them face-up, a mismatch flips them back after a short delay. ```ts type Card = { id: number; pairId: number; flipped: boolean; matched: boolean }; class MemoryGame { constructor(public readonly cards: Card[]) {} flip(cardId: number): 'wait' | 'match' | 'no_match' | 'already_flipped' { ... } get moveCount(): number { ... } get isComplete(): boolean { ... } reset(): void { ... } } function createDeck(pairs: number): Card[] { ... } // shuffles cards ``` **Requirements:** Only 2 cards can be in the "pending" state at once. Enforce a delay before non-matching cards are flipped back. ## Follow-ups 1. How do you prevent the user from clicking a third card while the mismatch delay is running? 2. How would you implement the shuffle to guarantee no card is adjacent to its pair? 3. How would you add a high-score board stored in localStorage? 4. How would you animate the flip without using external libraries (CSS 3D transform)?

What to Expect in the Nextdoor Phone Screen Round

The Nextdoor Software Engineer Phone Screen round has a specific calibration purpose distinct from other rounds in the loop. Across 15+ verified reports on LeakCode for this exact round type, the consistent expectations: clear scoping of the problem before diving into a solution, explicit reasoning about complexity, structured handling of edge cases, and the ability to discuss trade-offs between two reasonable approaches.

Reports tagged with the Phone Screen round at Nextdoor show recurring patterns in difficulty and topic distribution. The Phone Screen round is typically 45-60 minutes; the interviewer is calibrated against a specific rubric. The discriminator between candidates who advance and candidates who do not is rarely the final correctness of the answer. It is the path: did you clarify, did you verbalize your approach, did you handle edge cases, and did you communicate throughout.

How To Prepare for This Specific Round

Filter the questions below to the most recent reports (past 6-12 months). Questions tagged for this exact round type from this exact company at this exact role level are the highest-signal data available. Older reports may reference questions that have since rotated out of the company's pool.

Practice 4-6 representative problems from this set under timed conditions. The goal is not memorization (companies rotate questions); the goal is to internalize the patterns the interviewer typically reaches for and the depth of follow-up to expect. Reports on LeakCode also tag the typical follow-up depth at this round type, which is the discriminating signal between hire and no-hire calibration.

Phone Screen Round Timing and Format

The Phone Screen round at Nextdoor typically runs 45-60 minutes. Use the first 2-3 minutes to clarify requirements; you should never start coding or designing without verifying the input/output format, constraints, and edge cases out loud. Use the next 5-7 minutes to verbalize your approach before writing any code. The middle 20-30 minutes are implementation. Reserve the final 10 minutes for testing with concrete examples and discussing optimization or trade-offs.

Time budget discipline is one of the most reliable senior-vs-junior discriminators in this round. Strong candidates verbalize where they are in their budget out loud ("I've used about 20 minutes, I have 15 minutes left for testing and one optimization"). This signals engineering maturity to the interviewer and creates positive feedback they can capture in writing.

Common Failure Modes in This Round

Reports tagged "no hire" at Nextdoor Software Engineer Phone Screen commonly cite: coding silently without verbalizing approach, jumping to implementation before clarifying requirements, missing edge cases (empty input, single element, very large input), producing working code that the candidate cannot refactor when asked, and failing to test their solution with concrete examples before declaring done.

The single most predictive failure mode in 2025-2026 reports: not asking clarifying questions. Interviewers at all FAANG companies are explicitly trained to weight this dimension. Strong candidates ask 3-5 clarifying questions even on problems that look obvious; weak candidates dive into code immediately. The clarifying-question check is often the first signal recorded in the interviewer's notes.

See All 15 Questions from This Round

Full question text, answer context, and frequency data for subscribers.

Get Access