Upstart Software Engineer Interview Guide

Upstart Software Engineer interview prep: online assessment, technical screen, and a virtual onsite with a Project round, system design and behavioral.

Topics: Upstart, Software Engineer, Interview Guide

Author: PracHub

Published: 9/22/2026

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

Upstart Software Engineer Interview Guide

Upstart Software Engineer interview prep: online assessment, technical screen, and a virtual onsite with a Project round, system design and behavioral.

Questions in our bank by interview round

  • HR Screen6 questions
  • Online Assessment19 questions
  • Technical Screen7 questions

On this page0% read
01 · Overview

Interviewing at Upstart

Upstart runs a lending technology platform that uses machine learning models to assess credit risk, and bank partners use it to offer loans to consumers. Candidate reports name several platforms a Software Engineer may be aligned to: the Partner Integrations and Origination Platform, the Capital Marketplace, the Distribution Platform, and product lines such as Cash Line and Pricing. The engineering work behind them covers backend services and APIs, partner integrations, transaction processing and database consistency. Upstart candidates report 4 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.

Practice bank
32+ questions
Round types in our bank
3
Interview reports
5
02 · Difficulty

How hard is the Upstart Software Engineer interview?

From 32 labelled questions
  • Easy19%6 questions
  • Medium81%26 questions
  • Hard0%0 questions

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

Read 5 Upstart interview reports from candidates who went through this loop.

03 · Topic breakdown

What Upstart actually tests for

Share of 32 Software Engineer questions
  1. Coding & Algorithms81% · 26
  2. Behavioral & Leadership16% · 5
  3. Software Engineering Fundamentals3% · 1
04 · Question bank

The questions most likely to come up

32+ in the Upstart bank · sorted by popularity
  1. Solve Reported OA Coding ProblemsThe post describes several algorithm questions from an online assessment. The concrete problems that can be reconstructed are:Coding & AlgorithmsOnline AssessmentCodingMedium
  2. Discuss Compensation ExpectationsExplain your compensation expectations while keeping the discussion collaborative and tied to the role's scope and total package.Behavioral & LeadershipHR ScreenMedium
  3. Describe Your Python ExperienceDescribe your practical Python experience, including the kinds of systems or analyses you built, quality practices, and limits of your expertise.Software Engineering FundamentalsHR ScreenMedium
  4. Find max word letter spanImplement a function that, given an input text string, computes the maximum word letter span and returns bothCoding & AlgorithmsTechnical ScreenCodingMedium
  5. Demonstrate Project OwnershipDescribe a project you owned, from identifying the problem through delivery and follow-up.Behavioral & LeadershipHR ScreenMedium
  6. Unlock every Upstart questionModel solutions on all of them, plus the coding and SQL consoles.See Premium
  7. Solve Five OA Coding TasksThis is an online-assessment screen consisting of five independent coding tasks. Each task is self-contained — there is no shared state between them…Coding & AlgorithmsOnline AssessmentMedium
  8. Why This Company and RoleExplain what you understand about the company and why this particular role interests you.Behavioral & LeadershipHR ScreenMedium
  9. Decode an anagram sentence using vocabulary constraintsvocab: a list of lowercase words (the "dictionary")Coding & AlgorithmsTechnical ScreenCodingMedium
  10. Professional Introduction for a Recruiter ScreenGive a concise professional introduction that connects your current strengths, relevant experience, and reason for discussing this software…Behavioral & LeadershipHR ScreenMedium
  11. Reverse even numbers in a listGiven an integer array nums, remove all odd numbers and return the remaining even numbers in reverse order (preserving no other ordering constraints).Coding & AlgorithmsTechnical ScreenCodingMedium
  12. Sum Multiples of Three, Five, or SevenCoding & AlgorithmsOnline AssessmentPremiumMedium
  13. Implement four string-processing functionsCoding & AlgorithmsTechnical ScreenPremiumMedium
Practice 32+ Upstart questions

The 60-second brief

Upstart runs a lending technology platform that uses machine learning models to assess credit risk, and bank partners use it to offer loans to consumers. Candidate reports name several platforms a Software Engineer may be aligned to: the Partner Integrations and Origination Platform, the Capital Marketplace, the Distribution Platform, and product lines such as Cash Line and Pricing. The engineering work behind them covers backend services and APIs, partner integrations, transaction processing and database consistency.

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

What a Software Engineer does at Upstart

According to candidate reports, the work centers on high-throughput transaction processing, database consistency and integrations with external bank partners. The languages mentioned include Java, Ruby and JavaScript/TypeScript with React. Ruby on Rails, Sinatra and ActiveRecord come up as frameworks you may run into. Reported responsibilities also include code review, on-call rotations, production debugging and query or latency tuning. Senior and principal engineers also own service boundaries and technical direction.

In the interview, that background shows up as three kinds of preparation. The first is fast, readable solutions to practical coding problems under strict per-question time limits. The second is building and debugging a small working application in your own environment during the Project round. The third is design answers that deal directly with API contracts, schemas and the choice between strong and eventual consistency for financial data. Candidates report hiring across L4, L5/Senior and Principal levels, and design and leadership depth are expected to grow with seniority.

The Upstart interview process

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

Recruiter Screen

A recruiter conversation about your background and fit for the role. Use it to collect the facts that shape the rest of your preparation. Ask which team or platform the opening sits on, which level the loop is calibrated to (candidates report L4, L5/Senior and Principal), which platform the online assessment runs on, and what language and framework expectations apply to the Project round. Also confirm the location and hybrid expectations for the role on this call.

What it evaluates

  • Whether you can give a short, specific account of your background and why this company and role make sense for you
  • Whether the scope you describe lines up with the level the role is hiring for
  • Whether you have a considered answer when compensation expectations come up

How to prepare

  • Rehearse a professional introduction and a 'why this company and role' answer that refers to the lending platform and the team area you are interviewing for, not generic fintech enthusiasm
  • Prepare a compensation range with the components named, so a question about expectations gets a clear answer
  • Write down your questions in advance: target team, level, assessment platform, Project-round language/framework and location expectations
  • Pick the one project you will lead with later in the technical screen, and be able to summarize it in two sentences here

Online Technical Assessment

Candidates describe this as a timed set of coding challenges on a platform such as CodeSignal or CoderPad, with strict time limits for each question. The coding problems in the question bank for this role make good practice for this format, and they are mostly practical: string rewriting (replacing punctuation, grouping strings), array filtering and reordering, de-duplication that keeps first-appearance order, bounding boxes over coordinates, and billing or revenue simulations. Because each question has its own time limit, a correct brute-force solution that finishes is worth more than an optimal one left half-written.

What it evaluates

  • Whether each solution returns the right output for the stated examples and for the edge cases they leave out
  • Whether you finish the core logic within each question's limit before trying to optimize
  • Whether the code is readable enough to follow at a glance

How to prepare

  • Work through the bank's short problems (Filter Odds and Reverse Evens, String Replace and Grouping, Remove Duplicates While Preserving First-Appearance Order, Count Numbers Whose Successor Exists, Bounding Box From Coordinates) with a per-question timer you do not extend
  • For simulation-style problems such as the buffet revenue and cafeteria billing tasks, list the state variables and the order of events before writing code
  • Test against empty, single-element and duplicate-heavy inputs on every problem, since the prompt examples rarely cover them
  • If you run short on time, write the remaining approach as comments so the intent is visible

Technical Screen

Candidates report a session with a hiring manager or senior engineer. It combines a deep-dive into a past project with live coding, and sometimes system design. For the live-coding part, the reported coding questions for this role are useful practice because they turn on picking the right data structure: a custom stack that supports push, pop and a calculation over its elements, rolling statistics over a transaction stream using a map, and character-code differences between two long strings. Talk through your reasoning, write clean code and dry-run it against test cases.

What it evaluates

  • Whether you can explain the trade-offs in a project you drove, including what you chose not to do
  • Whether you choose maps, sets or stacks to match the access pattern, and can state the resulting time and space complexity
  • Whether you talk through your approach and dry-run the code before calling it finished

How to prepare

  • Prepare one project walkthrough covering the problem, your design decisions, the alternatives you rejected, what broke and what you measured
  • Practice the custom-stack pattern: store the aggregate-so-far with each element so push, pop and the query run in O(1). This works for min, max, sum, and mode with a count map (pop decrements the count and restores the stored mode). Median cannot be kept this way because it needs order statistics such as two heaps, so ask which calculation is meant before promising O(1)
  • Practice a rolling-statistics problem over a keyed stream with a map of running aggregates, and state what happens when a key disappears
  • Narrate brute force first, then the improvement, then trace one small input by hand before running anything

Virtual Onsite

Candidates describe a virtual onsite made up of several distinct interviews. It covers live algorithmic coding, system design, a practical Project round, a values-based behavioral interview and a final conversation with a hiring manager or engineering leader. In the Project round you build or extend a working application in your own local environment while sharing your screen. Examples include a React front end or a lightweight Sinatra or Rails back end, with database migrations and model relationships. For the system design interview, practice the reported design questions for this role: a multiplayer chess game, an asynchronous loan-decision API for bank partners, rate limiting for distribution APIs, a high-volume ledger schema and a notifications service with at-least-once delivery.

What it evaluates

  • In the Project round, whether you finish with a working feature, including persistence, validation and error handling, inside your own environment
  • In system design, whether you ask about business requirements, data volume and consistency guarantees before drawing the architecture
  • In the values interview, whether your stories show ownership, handling of ambiguity and constructive disagreement with specific actions
  • Whether your coding stays clear and tested even after earlier rounds the same day

How to prepare

  • Before the day, have a boilerplate app in your chosen stack connected to a local database (PostgreSQL or SQLite), with one migration and one model relationship already tested end to end
  • Rehearse building a small task-manager API with persistence against a short spec, then add input validation and error responses to it
  • For every design question you practice, say where you need strong consistency (ledger balances, loan decisions) and where eventual consistency is acceptable (reporting, notification status)
  • Prepare STAR stories for ownership, a production mistake, a tight deadline and a disagreement with product about technical debt

Questions Upstart 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 Upstart works from.

Data structures and algorithms

Ask which resource the problem actually takes away, because it is not always time. If the input does not fit in memory, the set you were going to build is gone and the bound that matters is space. If the data arrives once and cannot be revisited, anything needing a second pass is out whatever its complexity, and a constraint banning modification of the input removes the in-place trick that would otherwise be free. Naming the scarce resource first cuts the candidates down to a handful, and it stops you optimising a dimension the problem was never short of.

  • Implement a custom stack data structure that supports push, pop, and an arbitrary calculation over the elements in optimal time complexity.
  • Solve a mathematical word problem in code, optimizing for both time complexity and readability.
  • Given a list of integers and target constraints, find all unique combinations that satisfy a specific mathematical formula.
  • Write a function to find the character code differences between two long strings.

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.

  • How do you handle disagreements with product managers regarding technical debt versus feature delivery?
  • Describe a time when you had to meet a tight deadline under resource constraints. How did you prioritize tasks?

Other topics

A large share of these are really questions about evidence: why something is slow, or how much of something you would need. Convert the prompt into a number or an observation. For diagnosis, name the measurement that would tell two candidate explanations apart and say what each predicts before you collect it. For sizing, carry the units through and stop at one significant figure. Listing everything that could plausibly be true is what the weak version looks like. What separates the strong one is a hypothesis, the observation that would falsify it, and what the arithmetic already rules out before any new data arrives.

  • Implement input validation and error handling for a multi-step user registration form that connects to a backend service.
  • Design a scalable notifications service that handles millions of SMS and email alerts daily, ensuring at-least-once delivery.

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.

Add and backfill business_date on a live ledger table

ledger_entry holds 4 billion rows, is append-only, takes 10,000 inserts per second, and every reporting query currently derives the business date as posted_at::date. You must add business_date date NOT NULL, populated from the cutoff rule (17:00 in the account's own timezone), backfilled across all history, indexed, and cut over, with no write downtime and no long-held lock. Give the ordered migration steps with the lock each one takes, how you make the backfill restartable and throttled, and how you retire the old expression safely.

How a strong candidate works it

  • Add the column nullable and with no default. ALTER TABLE ... ADD COLUMN takes ACCESS EXCLUSIVE but is a catalogue-only change held for microseconds. The hazard is the lock queue, not the statement: a blocked ALTER waits behind one long reader holding ACCESS SHARE, and every query arriving afterwards queues behind the ALTER's pending ACCESS EXCLUSIVE, so set lock_timeout to a couple of seconds and retry rather than letting a metadata change take the table down.
  • Deploy the write path before the backfill, so new inserts populate business_date from the cutoff rule while reads stay on the old expression. The backfill then chases a closed set with a fixed upper bound instead of a moving target.
  • Backfill in bounded batches keyed by entry_id range, on the order of 50,000 rows per statement, committing between batches and recording the high-water mark in its own table so a killed run resumes instead of restarting. WHERE business_date IS NULL makes each batch idempotent, and the pacing is set by replica lag and dead-tuple growth rather than CPU, since each UPDATE writes a new row version and the WAL volume is proportional to the rows touched.
  • Install the constraint without a blocking scan: ALTER TABLE ... ADD CONSTRAINT ck_business_date CHECK (business_date IS NOT NULL) NOT VALID takes a brief ACCESS EXCLUSIVE and scans nothing, then VALIDATE CONSTRAINT takes SHARE UPDATE EXCLUSIVE and runs alongside reads and writes. On PostgreSQL 12 and later, SET NOT NULL can then use the validated CHECK and skip its own full scan; on 11 and earlier it always scans, so the CHECK is the migration on those versions.
  • Build the index with CREATE INDEX CONCURRENTLY, which avoids ACCESS EXCLUSIVE at the cost of two table passes, cannot run inside a transaction block, and on failure leaves an INVALID index that must be dropped and rebuilt rather than reused.
  • Cut over behind a flag: run the new and old expressions side by side for one reporting cycle and compare totals per day, since the cutoff rule will legitimately move entries near 17:00 across the boundary. Only once they reconcile do you retire the posted_at::date expression index, and you keep posted_at as the ordering key rather than repurposing it.

Follow-ups

  • Reporting now wants ledger_entry partitioned by business_date. Why can this not be another ALTER, and what is the migration instead?
  • Nightly totals move for the days around the cutoff change. How do you tell a correct restatement from a backfill bug?
  • The backfill is halfway done when a replica falls 20 minutes behind. What do you throttle, and what do you refuse to throttle?

Rebuild a statement with a running balance from entries alone

From ledger_entry(entry_id bigint and monotonic, account_id, direction, amount_minor, currency, business_date, posted_at) produce one month's statement for a single account: every entry in order, its signed amount, and the running balance after it, starting from a supplied opening balance. The account is a customer deposit, so a credit increases it. Also return the first business_date in the month on which the running balance went negative, or null if it never did. Write the query using window functions, state which frame you depend on, and say what makes the ordering deterministic.

How a strong candidate works it

  • Sign the amount first: CASE WHEN direction = 'credit' THEN amount_minor ELSE -amount_minor END, because the sign lives in direction and never in the column. State the convention out loud, since a customer deposit is a liability of the institution and a credit increases it, while for an asset account the same expression inverts.
  • Compute the running balance as SUM(signed) OVER (PARTITION BY account_id ORDER BY business_date, entry_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), then add the opening balance as a scalar. The opening figure is a constant for the statement, not a second window.
  • Be explicit about the frame, because it is the whole exercise: with an ORDER BY and no frame clause the default is RANGE UNBOUNDED PRECEDING AND CURRENT ROW, which includes every peer row tied on the ordering key. Ordering on business_date alone therefore reports the same end-of-day figure on every line of that day, and the statement still looks plausible.
  • Make the order deterministic with a column that has no ties: business_date has ties by construction, entry_id is monotonic and unique, and posted_at is neither guaranteed unique nor correct as an ordering key when a backdated entry posts late.
  • Get the first breach from the same computation rather than a second pass: wrap the running balance in a subquery and take MIN(business_date) FILTER (WHERE running_balance_minor < 0). LAG is the wrong tool here, because the question is about a level rather than a change.
  • Support it with an index on (account_id, business_date, entry_id) so the partition and the order both come from the index; then confirm in EXPLAIN that there is no Sort node above the index scan.

Expected result (25 min): One row per entry in date then entry_id order. The final row's running balance equals the opening balance plus the sum of all signed amounts in the month, to the minor unit. first_negative_date is the earliest business_date at which the ordered running balance dipped below zero, and null when it never does.

Check yourself

  • Sum the signed column independently with a plain aggregate and compare it against the last running balance; they must be equal.
  • The three entries sharing a business_date show three different running balances, which proves the frame and tiebreak are right.
  • Removing the ROWS frame reproduces the end-of-day artefact on exactly those three rows and nowhere else.
  • EXPLAIN shows no Sort node above the index scan on (account_id, business_date, entry_id).

Follow-ups

  • An entry for 3 March posts on 7 March, after the statement for that week was sent. Where does it appear, and what does the running balance do?
  • The same statement has to be reproducible a year from now. What stops it changing, and what would silently change it?
  • At what account size does deriving this per request stop being viable, and what would you materialise first, a daily closing balance or a monthly one?

Detect duplicate-charge bursts in an out-of-order authorisation stream

Authorisations arrive as (instrument_token_id, amount_minor, currency, event_time, arrival_time) at roughly 3,000 per second, up to 60 seconds late and out of order. Flag any token with three or more authorisations of identical (amount_minor, currency) inside any 10-minute window of event time. Report each flag once, as early as correctness allows. State memory per key and in total, how late an event you will accept, and what you do with one that arrives after you have already reported — or already declined to report — that window.

How a strong candidate works it

  • Key state by (instrument_token_id, amount_minor, currency), not by token: the predicate is about identical amounts, so the window belongs to the triple. Each key holds its own event-time-ordered deque.
  • In-order, this is two pointers: on insert, pop from the front while front <= new - 10 min, then flag if the deque reaches length 3. Amortised O(1) per event, memory proportional to that key's window occupancy.
  • Out-of-order arrival breaks append-only monotonicity, so insert in position instead. With lateness bounded at 60 seconds the insertion point is always near the tail, so a short sorted vector or a 600-bucket per-second ring keeps it O(w) with tiny w; a balanced tree per key is correct but over-built for a one-minute reorder.
  • Drive decisions off a watermark of max(event_time seen) - 60 s, never off wall clock. Anything older than the watermark is too late to change an answer and is counted in a late_dropped metric. Without an explicit watermark you have still chosen a lateness policy — you just cannot state it or test it.
  • Report-once needs its own state: per key, a set of already-flagged 10-minute window ids. A later event inside an already-flagged window must not re-flag, and a late event that completes a window you never flagged must flag — which is why state is retired at window close plus the lateness bound, not at window close.
  • Size it: state lives 660 seconds, so at 3,000 events per second there are about 1.98 million in flight, plus one flagged-window set per active key. Bound total memory explicitly and shed by key age, and say what shedding costs — a shed key can miss a flag, making the threshold a product decision rather than a tuning knob.

Expected result (40 min): Fixture 1 flags exactly once, at the t+9 event; the t+11 event does not flag under the half-open rule and does under the closed one, which is the boundary the fixture exists to pin. Fixture 2 yields the same single flag with the same window id. Fixture 3 yields no flag and late_dropped == 1. All twenty shuffles produce an identical flag set.

Check yourself

  • Replaying the same events in any arrival order within the lateness bound produces identical flags — the only property that makes this job re-runnable.
  • Per-key state never exceeds that key's events within 660 seconds; assert it rather than hope.
  • Every flag's window id derives from event time alone; arrival_time appears only in the watermark computation and the lateness metric.

Follow-ups

  • Make the threshold and window configurable without rebuilding all in-flight state on every change. What does that constrain in the data structure?
  • Two stream partitions hold events for the same token. What does that force the partitioning key to be?
  • An event arrives three hours late. Does any answer change, and who is told?

Capture endpoint that survives concurrent duplicate retries

POST /payments/{intent_id}/capture carries an Idempotency-Key header and an amount. Callers retry on timeout, and two retries can land concurrently on different instances. You have idempotency_key(id, scope, key, UNIQUE(scope,key), request_fingerprint bytea, status in_progress|completed|failed, response_status, response_body jsonb, locked_at, completed_at, expires_at). The processor capture takes 200 to 2,000 ms. Design the path so exactly one capture reaches the processor, every duplicate receives the identical response, and a crash between the processor call and your commit converges. Name the single statement that is the concurrency control.

How a strong candidate works it

  • The concurrency control is INSERT INTO idempotency_key (...) VALUES (...) ON CONFLICT (scope, key) DO NOTHING RETURNING id, and it must commit before the processor call. A returned row means you own the effect; zero rows means you lost and must read the winner's result. A SELECT-then-INSERT check cannot substitute: two requests both read 'absent' and both proceed, and the window is exactly the concurrency you are defending against.
  • Commit the in_progress row in its own short transaction. A concurrent duplicate insert blocks on an in-flight conflicting insert until that transaction ends, so wrapping the 2 s processor call in the same transaction turns every duplicate into a 2 s lock wait and a retry storm into pool exhaustion.
  • Define loser behaviour per status rather than uniformly: completed replays response_status and response_body unchanged; in_progress returns 409 with Retry-After and performs nothing; failed splits by cause, since a terminal processor decline should replay but a transport failure should let the key be retried. Getting this wrong in the safe direction (replay a decline) is better than returning an error for a capture that succeeded.
  • Fingerprint the canonicalised body with SHA-256 and compare on every hit. Same key with a different amount is a client bug and must return 409 or 422, never the cached response, because returning the cached body silently captures the old amount and looks successful.
  • Pass the same key to the processor so deduplication holds end to end, and generate it once at the originating caller. A key regenerated per attempt leaves every line of idempotency code in place while disabling the mechanism entirely.
  • Converge after a crash by querying the authoritative side rather than guessing: a reaper picks up rows in_progress past locked_at plus a bound, asks the processor for that key or the intent's processor_reference, and completes the row from the answer. Set expires_at longer than the caller's full retry schedule and document that a replay after expiry is a new request.

Expected result (30 min): Exactly one processor call across the 50 requests. One request returns the capture; the other 49 either replay the stored body unchanged or return 409 in_progress, and none returns a 500 or a second capture. The changed-amount request returns 409 or 422 and never the cached body. After the crash, the reaper completes the row from the processor's own answer, leaving exactly one capture.

Check yourself

  • Time the 49 losers: if they each take about 1,500 ms, the winner is holding the key row inside the transaction wrapping the processor call.
  • The stub's call counter reads 1, not 1 plus a retry.
  • Swapping the constraint for a check-then-insert reproduces two captures under the same load; keep that as the regression test rather than trusting the fix.

Follow-ups

  • The processor does not honour idempotency keys. What is the end-to-end design now, and what can you no longer promise?
  • Two merchants send the same key value. What makes that safe?
  • You keep keys for 24 hours at 3,000 requests/s. Size the table and the index, and say what expires them.

Settlement postings plateau at 310 per second and deadlock

Ledger postings against one pooled merchant settlement account plateau at about 310 committed transactions per second. Adding workers beyond 24 raises latency linearly and leaves throughput flat. Separately, about 0.4% of two-account transfers abort with SQLSTATE 40P01. Each posting takes SELECT ... FOR UPDATE on the materialised balance row, validates a floor, inserts the entries, then updates the balance. Explain both numbers, give the fix for each, and state precisely what sharding the hot balance would cost the floor check.

How a strong candidate works it

  • Compute the ceiling instead of guessing. A row-level exclusive lock serialises every transaction touching that row, so the maximum committed writes per second is 1 divided by the lock hold time, where hold runs from FOR UPDATE to COMMIT and includes the entry inserts, the WAL flush and anything else inside the transaction. 310 per second implies about 3.2 ms held. Measure it via pg_locks joined to pg_stat_activity rather than inferring it.
  • Recognise what the flat-throughput, rising-latency curve proves. Past the ceiling, extra workers only lengthen the wait queue; that is serialisation, not saturation, and no amount of CPU, replicas or pool size changes it. Establishing this rules out the three most common wrong fixes before proposing anything.
  • Shorten the critical section before sharding anything. Take the lock last, never hold it across an application round trip or a processor call, and replace SELECT-then-UPDATE with one conditional statement: UPDATE balance SET amount_minor = amount_minor - $1 WHERE account_id = $2 AND amount_minor - $1 >= floor_minor. It needs no prior read and holds the row only for that statement, so halving hold time doubles the ceiling for free.
  • Treat the 40P01 as a separate defect with a separate fix. Two transfers moving money in opposite directions between accounts A and B acquire the two row locks in opposite orders and wait on each other until the detector aborts one. Acquiring locks in a deterministic order, such as ascending account_id, makes the cycle impossible rather than merely rarer; a bounded retry on 40P01 remains prudent but is no longer the mechanism.
  • Only then shard, and price it honestly. N sub-rows multiply the ceiling by roughly N, but the floor becomes a predicate over N rows that a single-row conditional UPDATE cannot express. Either each sub-row carries its own floor, which over-restricts by refusing a payment while funds sit on another shard, or you move to SERIALIZABLE with a bounded retry on 40001 across the sub-rows. Establish first whether this pooled clearing account has a floor at all, because if it does not, sharding is nearly free and the whole trade-off disappears.

Follow-ups

  • At what N does rebalancing funds between sub-rows cost more than the throughput it buys?
  • How would you measure lock hold time in production without attaching a profiler?
  • Does moving to SERIALIZABLE eliminate the 40P01 aborts?

Estimate a reconciliation rebuild you have never attempted

You are asked how long it takes to replace a reconciliation service matching 30 million settlement lines a day against the ledger, including a bounded fuzzy fallback for netted fees and an ageing model for breaks. You have never built one. Produce an estimate, the range around it, and the two or three unknowns that dominate that range. Then describe a time you estimated unfamiliar work: what you did in the first day to shrink the range, what you committed to publicly, how far off you were, and what you would tell the requester differently now.

How a strong candidate works it

  • The probe is whether you can be useful under uncertainty without either refusing to estimate or inventing false precision. Give a number with an explicit range and the basis for both, then immediately name what would move it, rather than asking for two weeks of discovery first.
  • Decompose into parts with different uncertainty profiles. The hash join on (external_reference, amount_minor, currency, business_date) over 30 million lines is well understood engineering and estimates tightly; the fuzzy fallback for netted and fee-adjusted lines does not, because its scope is defined by whatever the files actually contain; the ageing and break workflow is mostly operations-facing surface area, which estimates by counting screens and states.
  • Name the dominating unknowns concretely: how many distinct file formats and cutoff conventions the sources use, what fraction of lines are netted rather than itemised, and whether business_date is derivable from any field in the file or must be reconstructed from the cutoff rule. Each is a factor on the fuzzy path, not a percentage on the whole.
  • Describe the first-day range-shrinking work, which is the part that separates strong from generic: take one real file, count distinct formats, measure the netted fraction, and attempt the exact join on a single day of postings to see what the residual actually is. One day of that typically converts a 3x range into something near 1.5x.
  • Commit in a form that survives being wrong: a range plus a checkpoint date at which you will replace it with a narrower one, and an explicit statement of what you will cut first if the range turns out to be optimistic.
  • In the retrospective half, give the real numbers: the estimate, the actual, and the specific thing that consumed the difference. Answers that were within 10 percent are less informative than answers that were 2x off for a nameable reason.

Follow-ups

  • The requester wants one number, not a range, for a board deadline. What do you give them?
  • Your one-day probe finds 40 percent netted lines instead of the 5 percent you assumed. What changes in the plan, not just the estimate?
  • What do you cut first if you are at the deadline and the fuzzy fallback is not done?

Where candidates lose points

Arriving at the Project round with a local environment that has never run a migration end to end

Time spent on database connection errors, package-manager mismatches or a boilerplate that does not boot comes straight out of your building time. A few days before, create the app in the stack you will use, connect it to a local database, run a migration, add one model with a relationship and hit one endpoint. Then restart your machine and repeat it from a cold start so you know it works on interview day.

Breaking model relationships with a naming or namespace mistake in Rails/ActiveRecord

Candidates report debugging a broken migration or model relationship, and a namespacing mistake in ActiveRecord can quietly break associations. If you use Rails, check table names, foreign keys and class_name/namespace settings as you create each model, and confirm each association in a console before building on it. If you use another stack, practice the same habit with its ORM.

Chasing the optimal solution on a timed assessment question and submitting nothing that passes

The online assessment has a separate time limit for each question. Write the simplest correct version first, run it against the examples plus an empty and a single-element input, and only then improve it. Most of the bank's short coding problems (filtering, string rewriting, de-duplication, bounding boxes) have a direct linear solution, so a long search for something clever usually means you misread the prompt.

Designing the ledger or loan-decision system without stating its consistency model

The reported design questions include a high-volume ledger schema and an asynchronous loan-decision API for bank partners. Say early which writes need ACID guarantees (balance changes, a decision recorded once), and which reads can be eventually consistent (dashboards, notification status). Then show how the schema and API enforce that: unique keys, idempotent retries and an explicit state for a partner decision that is still pending.

Describing a past project in the technical screen without the trade-offs

A walkthrough that lists technologies and team size tells the interviewer little about your judgment. For the project you lead with, prepare the two or three decisions that mattered, the alternative you rejected for each and why, and one thing that went wrong in production and how you handled it. A reported behavioral question asks directly for the most technically complex project you drove and its trade-offs.

Breadth then depth, for a generalist facing a mixed loop

Four days sample coding, design, fundamentals and the practical rounds at deliberately shallow depth, which is enough to surface the topics you did not know were in scope. That map, rather than a guess made on day one, decides where the last three days go.

Day 1 — Assessment-style coding: strings and arrays

  • Solve Filter Odds and Reverse Evens, String Replace and Grouping, Remove Duplicates While Preserving First-Appearance Order and Count Numbers Whose Successor Exists, each with a per-question timer you do not extend
  • Write down the edge cases the prompt examples leave out (empty input, a single element, all duplicates, trailing punctuation) and test every solution against them
  • Solve Bounding Box From Coordinates in one pass and state its complexity out loud

Deliverable: Five timed solutions, each marked finished or late, with an edge-case list attached.

Day 2 — Data-structure coding for the live-coding interviews

  • Implement the reported custom stack with push, pop and a constant-time min (then sum) by storing the aggregate-so-far with each element, and explain why this works for aggregates you can update from the previous value (min, sum, or mode with a count map) but not for median, which needs order statistics such as two heaps
  • Write rolling statistics over a transaction stream using a map keyed by account, then extend it to a sliding window
  • Solve the reported unique-combinations problem with backtracking and duplicate skipping, and the character-code differences between two long strings
  • Optional depth: work through the existing out-of-order stream exercise (drill-coding-3) to practice windows and watermarks

Deliverable: Four solutions narrated aloud with brute force, improvement and complexity stated for each.

Day 3 — Project round: environment and a working API

  • Set up a boilerplate app in the stack you will use (for example Rails, Sinatra, Spring Boot or a React front end with an API), connected to a local database
  • Build a task manager like the reported one against your own practice spec: create, list, update and delete tasks, persisted to the database, plus one migration that adds a column
  • Restart from a cold start and confirm the app boots, migrates and serves a request without fixes

Deliverable: A tested local project that runs from a cold start, plus a written checklist of setup steps.

Day 4 — Project round: validation, refactoring and debugging

  • Add input validation and error handling for a multi-step registration form that posts to your back end, returning clear field-level errors
  • Refactor a React component to reduce unnecessary re-renders and simplify its state, and note what changed and why
  • Deliberately break a migration or a namespaced model relationship, then fix it while narrating what you check first

Deliverable: Validation and error paths working in your project app, plus a short log of the break-and-fix debugging session.

Day 5 — System design: ledger and partner APIs

  • Design the schema and consistency model for a high-volume ledger, and state which operations need strong consistency and which reads can lag
  • Design the API for asynchronous loan decisions from external bank partners: request, callback or polling, idempotency and the pending state
  • Work through the existing idempotent capture exercise (drill-design-4) and the running-balance SQL exercise (drill-sql-2) to check your schema reasoning

Deliverable: Two design sketches, each with a schema, API contract and a stated consistency choice.

Day 6 — System design: throughput and real-time systems

  • Design a notifications service for SMS and email with at-least-once delivery: queueing, retries, deduplication on the consumer and delivery status
  • Design rate limiting for distribution APIs: choose an algorithm, where the counter lives and what a rejected caller receives
  • Design a multiplayer online chess game covering the database schema, API endpoints, move validation and state synchronization

Deliverable: Three designs, each opening with the clarifying questions you would ask about requirements, volume and consistency.

Day 7 — Behavioral, the project deep-dive and a mock onsite

  • Prepare STAR answers for the reported prompts: most complex project and its trade-offs, a tight deadline, a disagreement with product over technical debt, a production mistake and a disorganized codebase
  • Rehearse your technical-screen project walkthrough, including rejected alternatives
  • Run a back-to-back mock of one coding problem, one design prompt and one behavioral answer, and note where your structure slipped between them

Deliverable: Five STAR stories on cards, one rehearsed project walkthrough and notes from the mock loop.

Frequently asked questions

Is this an official Upstart interview guide?

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

How difficult is the Upstart Software Engineer interview?

Candidates describe most individual coding questions as easy to medium. The difficulty comes from the strict per-question time limits on the online assessment and from building a working feature live in the Project round. Prepare for speed and finishing, not only for hard algorithm topics.

What is the Project round, and how should I prepare for it?

Candidates describe building or extending a working application, such as a simple web app or API, live in their own local environment while sharing their screen. Before the interview, set up a boilerplate app in your preferred language and framework (for example React, Rails or Spring Boot), connect it to a local database, and test a migration and a model relationship from a cold start.

How is my level (L4, L5/Senior, Principal) decided?

Candidates report hiring at L4, L5/Senior and Principal. Reports say the level comes from performance across the onsite, with system design and the behavioral/values interview weighing most. If you are targeting senior or principal, prepare design answers with explicit trade-offs and stories where you led technical decisions. Ask your recruiter which level the loop is set to.

What kinds of coding problems should I practice?

The bank for this role is mostly practical: string rewriting and grouping, array filtering and reordering, de-duplication that preserves order, bounding boxes, and billing or revenue simulations. Reported coding questions also include a custom stack with a calculation over its elements, rolling statistics with a map, and combination search. Practice picking between hash maps, sets and stacks, and stating complexity.

Which system design topics come up?

Reported design questions include a multiplayer online chess game, an API for asynchronous loan decisions from bank partners, rate limiting for distribution APIs, a high-volume ledger schema and consistency model, and a notifications service with at-least-once delivery. For each one, cover the schema, the API contract, and where you need strong versus eventual consistency.

Keep practising

More questions candidates ask

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

Candidates describe most individual coding questions as easy to medium. The difficulty comes from the strict per-question time limits on the online assessment and from building a working feature live in the Project round. Prepare for speed and finishing, not only for hard algorithm topics.

Candidates describe building or extending a working application, such as a simple web app or API, live in their own local environment while sharing their screen. Before the interview, set up a boilerplate app in your preferred language and framework (for example React, Rails or Spring Boot), connect it to a local database, and test a migration and a model relationship from a cold start.

Candidates report hiring at L4, L5/Senior and Principal. Reports say the level comes from performance across the onsite, with system design and the behavioral/values interview weighing most. If you are targeting senior or principal, prepare design answers with explicit trade-offs and stories where you led technical decisions. Ask your recruiter which level the loop is set to.

The bank for this role is mostly practical: string rewriting and grouping, array filtering and reordering, de-duplication that preserves order, bounding boxes, and billing or revenue simulations. Reported coding questions also include a custom stack with a calculation over its elements, rolling statistics with a map, and combination search. Practice picking between hash maps, sets and stacks, and stating complexity.

Reported design questions include a multiplayer online chess game, an API for asynchronous loan decisions from bank partners, rate limiting for distribution APIs, a high-volume ledger schema and consistency model, and a notifications service with at-least-once delivery. For each one, cover the schema, the API contract, and where you need strong versus eventual consistency.

UpstartSoftware EngineerInterview Guide