← Stripe Interview Insights

Stripe·Software Engineer·Onsite - System Design / Architecture·Senior

SeniorPrefer not to say
Jun 2026

Summary

Stripe system design round for a software engineer role. One meaty question about role-based access control with account hierarchies, and then a lot of back-and-forth on indexing strategy and complexity tradeoffs. Left feeling like I could have structured the complexity analysis better.

Questions Asked (2)

Q1

You have a list of (userId, accountId, role) assignments and an account hierarchy where roles inherit downward from parent to child accounts. Given an accountId and a required set of roles, return all users who hold every role in that set, either directly on the account or through any ancestor account.

System DesignAlgorithms & Data StructuresTechnical Trade-offs
Author's notes

This took me a minute to fully parse.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Clarify the input format and constraints, then propose an efficient solution that preprocesses the account hierarchy and role assignments. For each query, traverse the ancestor chain of the given account, collect the union of roles from the account and its ancestors, and filter users who have all required roles. Discuss trade-offs between preprocessing and query-time computation, and consider scalability for large datasets.

Pro tip: Mention that you would precompute the transitive closure of the account hierarchy or use a materialized path to quickly get all ancestors, and that you would index role assignments by account and role to speed up lookups. Also, discuss how to handle dynamic updates to roles or hierarchy.

1. Clarify requirements and constraints

Ask about the size of the data, frequency of queries, whether the hierarchy is static or dynamic, and the expected output format. Confirm that roles inherit downward and that a user must have every role in the set, either directly or via ancestors.

2. Design data structures

Propose storing the account hierarchy as a tree with parent pointers or a materialized path. Store role assignments in a hash map keyed by accountId, with values as sets of (userId, role) or separate maps for role-to-users and user-to-roles.

3. Outline the algorithm

For a given accountId, traverse up the ancestor chain (including itself) to collect all relevant role assignments. For each required role, find the set of users who have that role on any of these accounts. Intersect these sets to find users who have all required roles.

4. Optimize and discuss trade-offs

Consider precomputing ancestor lists or using caching for frequent queries. Discuss time and space complexity, and how to handle updates (e.g., if a role is added/removed, or hierarchy changes). Mention indexing strategies for large-scale systems.

5. Test and validate

Walk through an example to verify correctness, including edge cases like no ancestors, empty role set, or users with roles on multiple ancestors. Discuss how to handle duplicate roles and ensure efficient intersection.

Key Points to Mention

  • Account hierarchy traversal: using parent pointers or materialized paths to efficiently get all ancestors.
  • Role inheritance: roles on ancestor accounts apply to descendant accounts, so union of roles across ancestors is needed.
  • Efficient intersection: using hash sets to intersect user sets for each required role, minimizing time complexity.
  • Preprocessing vs. query-time computation: trade-offs between precomputing ancestor-role mappings and computing on the fly.
  • Scalability: indexing strategies (e.g., by accountId and role) and handling large datasets with distributed systems.
  • Dynamic updates: how to handle changes to roles or hierarchy without full recomputation, e.g., incremental updates or versioning.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

Walk through the tradeoffs between walking ancestors at query time versus precomputing a rolled-up index, and how each approach scales with the number of users, ancestors, and roles in the filter set.

Technical Trade-offsSystem DesignData Modeling
Author's notes

I preferred the ancestor-walk approach and said so, mostly because precomputed rollups get painful when the hierarchy changes.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by framing the core tradeoff: query-time ancestor walking is flexible and simple but costs latency and load per query, while precomputed rolled-up indexes are fast to read but expensive to maintain and can become stale. Then analyze how each scales with users, ancestor depth, and role filter cardinality, and conclude with a hybrid recommendation based on read/write patterns and consistency needs.

Pro tip: Quantify the tradeoff with concrete numbers (e.g., 'a 10-deep hierarchy means 10 lookups per query, so at 10k QPS that's 100k extra reads/sec') and mention that Stripe-like systems often use a hybrid: precompute for hot paths and fall back to walking for rare or deep queries.

1. Define the two approaches

Briefly describe query-time ancestor walking (recursive/iterative traversal up the hierarchy per query) and precomputed rolled-up index (materialized ancestor-role mappings updated on write).

2. Analyze query-time walking

Discuss its scaling: O(depth) per query, so latency grows with ancestor depth; load on the datastore grows with QPS and depth; simple to implement and always consistent, but expensive for deep hierarchies and high read volume.

3. Analyze precomputed index

Discuss its scaling: O(1) read per query, but write cost grows with number of ancestors and roles (fan-out on updates); storage grows with users × ancestors × roles; risk of staleness and complex invalidation.

4. Compare across dimensions

Contrast how each scales with number of users (read/write volume), ancestor depth (latency vs update fan-out), and role filter cardinality (filtering efficiency and index size).

5. Recommend a hybrid or context-dependent solution

Propose a hybrid: precompute for shallow/hot paths, walk for deep/rare queries; or use caching with TTL; emphasize choosing based on read/write ratio, consistency requirements, and hierarchy depth.

Key Points to Mention

  • Latency vs throughput: query-time walking adds O(depth) latency per query; precomputed index gives O(1) reads but higher write amplification.
  • Scaling with users: more users increases read QPS (favors precompute) and write volume (favors walking if updates are frequent).
  • Scaling with ancestors: deeper hierarchies increase query-time cost linearly; precompute update cost grows with fan-out (ancestors × roles).
  • Scaling with roles in filter set: precomputed index may need to store role-ancestor pairs, increasing storage and update cost; query-time can filter dynamically.
  • Consistency and staleness: precomputed indexes can be stale; walking is always consistent but may be slower.
  • Hybrid approaches: cache hot paths, precompute for shallow levels, fall back to walking for deep or rare queries.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.