Software Engineers at Karat build and maintain the infrastructure behind its technical interviews. Reported work includes the Karat Studio collaborative coding environment, real-time video streaming services and automated grading systems, with real-time synchronization, data security and high availability as the recurring engineering problems.
The title covers more than one kind of seat. One reported variant is a Community Engineer role within the Brilliant Black Minds initiative, building tools, mock-interview platforms, community portals and feedback loops for aspiring Black software engineers. Another is Senior Deployment Engineering, building custom integrations, APIs and data pipelines between Karat's interviewing infrastructure and enterprise applicant tracking systems, and working with external engineering leaders on secure data ingestion. Across variants, reported work includes contributing to Karat Studio, taking part in code reviews, and working with product managers, UX designers and operations teams who support the Interview Engineers.
The listed must-have skills are proficiency in Python, Java, Ruby or JavaScript/TypeScript, plus backend development, RESTful API design and relational databases. The nice-to-haves are AWS or GCP, Docker and Kubernetes, React, and test automation tools such as Selenium or Playwright. Use the recruiter call to find out which seat you are interviewing for. Then weight your preparation toward it: API and integration design for deployment work, front-end review for React-heavy seats.
Candidates describe a standardized interview format. They report that coding questions come as a sequence of parts that build on each other, and that they run their code against pre-configured test cases in the Karat Studio IDE. In practice, reach a correct first part quickly, write it as small helpers the follow-ups can extend, and test as you go.
Recruiter Call
reportedCandidates describe a first call with a recruiter about the role and fit. This title covers several different jobs: product work on the Karat Studio collaborative coding environment, deployment work integrating Karat's platform with enterprise clients, and community tooling within the Brilliant Black Minds initiative. Use the call to find out which one this seat is. Also ask about the next steps: whether the Karat Qualify test comes first, when the Karat Core interview is scheduled, and what the onsite rounds cover for this team. Ask which languages the coding environment supports and whether looking up syntax is allowed. That way the later rounds hold no logistics surprises.
What to demonstrate
- Whether your experience maps to the specific seat (Studio product work, deployment and integrations, or community tooling) rather than to the whole posting
- Whether you can describe backend, REST API and relational-database work you have done in concrete terms, since the role requirements list those as must-haves
- Whether what you want next matches the seat, for example integration work with external engineering teams versus product work on the core platform
How to prepare
- Mark every line of the posting as done, adjacent or new, and write one sentence for each adjacent line naming the closest thing you actually built
- Prepare a short account of one API you designed and one database schema you owned, with the trade-off you made in each
- Bring questions that change your preparation: which seat this is, whether Qualify comes before Core, which languages the IDE offers, whether lookups are allowed, and what the onsite covers
Karat Qualify
reportedCandidates describe Karat Qualify as a 15-minute multiple-choice test on general coding logic, algorithms and backend fundamentals. You take it on your own, with no live interviewer. Candidates report that some start here instead of with the recruiter call, and that passing opens scheduling for the Karat Core interview. Multiple-choice against a short clock is a different skill from live coding. You need to read a snippet and know its output or complexity without running it, and to rule out wrong options quickly instead of deriving every answer from scratch.
What to demonstrate
- Reading code logic correctly without executing it, including loop bounds, off-by-one behaviour and mutation
- Recognising the time and space complexity of standard algorithms and data structures on sight
- Backend fundamentals; the reports give no specifics, so HTTP, REST and relational-database basics are the safe core to review
How to prepare
- Build a one-page complexity table for arrays, hash maps, balanced BSTs, heaps, sorting, and BFS/DFS over V vertices and E edges, and quiz yourself from memory
- Predict the output of ten short snippets in your main language before running them, and log every miss by topic
- Refresh HTTP methods and status codes, what an index speeds up and what it costs on writes, and inner versus left joins
Karat Core Interview
reportedCandidates describe this as a live video session of about 60 minutes with a trained Karat Interview Engineer. It opens with a brief introduction and a short technical quiz or system design discussion, followed by a coding challenge that starts with an easy problem and gets harder as you progress. You write code in the Karat Studio IDE and run it against pre-configured test cases during the session. Reports also say you may look up basic syntax and library documentation while coding, and that you can request a redo with a different Interview Engineer and new questions within 24 hours. Confirm both with your recruiter before relying on them. Later parts build on earlier ones, so aim for a correct first part, reached quickly, in code the follow-ups can extend.
What to demonstrate
- Short, accurate answers to CS fundamentals such as BFS versus DFS complexity, hash table versus balanced BST search, and garbage collection in Java
- A working first part, tested against the provided cases, finished early enough to reach the follow-up parts
- Code split into helpers, so a follow-up changes one function instead of forcing a rewrite
- Saying your approach, edge cases and complexity out loud before and while you type
How to prepare
- Rehearse a short spoken answer for each reported fundamentals question until each one fits comfortably in under a minute
- Practise multi-part problems in one sitting, such as the grid progression from neighbour coordinates to BFS path existence to backtracking string search, reusing one neighbour helper
- Code in a plain editor without autocomplete, and run tests after each helper rather than at the end
- Open the Karat Studio environment from your preparation materials and learn how to select a language, run the test cases and read console output
Onsite Loop
reportedCandidates describe the onsite loop as several rounds with internal Karat engineers and managers, reported to run three to four hours in total. The rounds cover system architecture, practical coding, collaborative code reviews and behavioural scenarios. The reports do not tie any specific question to this stage, so prepare by category: use the reported design and code-review questions in this guide as practice material without assuming where they will come up. Change your approach between rooms: in coding, finish and test; in design, agree requirements before drawing architecture; in behavioural answers, name the people and the decisions.
What to demonstrate
- Whether a design answer starts from requirements and failure behaviour (callers, limits, retries, what happens when a dependency is down) before choosing components
- Whether a code review finds concrete bugs, performance issues and security problems, and explains each fix and how to verify it
- Whether practical coding ends with something that runs and has been checked against an edge case
- Whether behavioural answers name your own decision, the people involved and a checkable outcome
How to prepare
- For system architecture, work through the reported design questions as category practice; for the rate-limiting API, write the contract end to end: how the caller is identified, the limit response (429 with Retry-After), and what the client does next
- For the reported notification and code-execution designs, state how a retry avoids duplicate work and what happens when one channel or worker pool is down, before drawing queues
- Review a piece of your own old code for style, security and testability, then refactor one function into testable pieces and explain each change
- Prepare four behavioural stories: unclear requirements, a project in trouble, a code review you led, and a performance decision
9 candidate reports. Individual accounts describe a particular role and hiring cycle.
Karat Software Engineer interview with three English and three coding questions
My Karat process began with a structured sequence of questions that felt a little relentless. After the initial stages, I answered three English questions and then moved straight into three coding problems. The first coding prompt asked whether a solution met the requirements. I was then asked more focused computer science questions about time and space complexity. The other coding problems were…
Read full experienceKarat Software Engineer interview with a moderate algorithm question
The interview started with a casual introduction from the interviewer, which made the conversation feel less cold. I then talked through my background, including my achievements, previous experiences, and how I’d handled challenges on earlier projects. It felt like that discussion was meant to provide context before the technical portion. Afterward, I worked through a moderate algorithm question.…
Read full experienceKarat Software Engineer interview: one-hour live coding and system design session
The process started with a short, multiple-choice qualifying test. I could choose topics such as backend, general coding logic, or algorithms and data structures. After I passed, I was invited almost immediately to schedule the actual interview. The main technical interview was a live online video session that lasted about an hour. It combined discussion and analysis questions with a system desig…
Read full experienceKarat Software Engineer interview: written Splunk exam and video problem
I started with a written exam sent by email. It focused directly on Splunk-related engineering topics. I completed it and thought I had passed, so I moved on to a video round where I solved a problem during the call. Even after that, I couldn't move forward, and the rejection left me more puzzled than informed. What bothered me most was the uncertainty about the role. I didn't know which position…
Read full experienceKarat Software Engineer interview with learning materials before rejection
I was surprised by how much Karat tried to include "learning" before making a final decision. What they called onboarding felt like an extension of the interview process. I studied their learning materials for a while and completed a couple of practice interviews, then still got rejected after about a week. The part that threw me off was that it didn't feel like optional preparation. It felt like…
Read full experiencePracHub editorial advice for the preparation topics above.
Polishing the first part of a multi-part coding question until the follow-up parts never arrive
Candidates describe the Karat Core coding challenge as a sequence that starts easy and builds, and you only reach the later parts by getting through the earlier ones. Get a correct, tested first part, state its complexity, and move on. Mention the optimisation you would make rather than making it. To practise, run the grid progression from the question bank against a timer you do not extend: Neighbor Coordinates for Zeros, then Path Existence in 2D Grid with BFS, then 2D Grid String Search with backtracking.
Writing part one as a single block with hardcoded sizes and targets, then rewriting it when the follow-up changes the input
Because the parts build on each other, split parsing, the neighbour or move function, and the search into separate helpers from the start, and pass sizes and targets in as parameters. Then when a follow-up asks for every path instead of one, or a large-input version of a string parser, you change one function instead of starting over.
Writing the whole solution before running it against the provided test cases in Karat Studio
Candidates report running their code against pre-configured test cases during the session, so run it after each helper works. When a case fails, read its input before changing any code. Explore the Karat Studio environment from your preparation materials beforehand: language selection, running tests, and console output. Keep inline comments light, because some candidates report the IDE mishandling heavily commented code.
Giving slow or vague answers in the CS fundamentals segment
Reported questions include BFS versus DFS time and space complexity, searching a balanced BST versus a hash table, memory allocation and garbage collection in Java, and REST versus other protocols. For each, prepare an answer of two or three sentences with the exact complexity and one case where the answer changes. For example: both traversals take O(V+E) time, but BFS holds up to a whole level in its queue while DFS holds one path. A hash table lookup is O(1) on average and O(n) when many keys collide, while a balanced BST is O(log n) and keeps its keys in order. Say each answer aloud until it is short.
Opening a reported design question, such as the rate-limiting API or the notification system, with boxes and queues instead of requirements and failure behaviour
The rate-limiting prompt asks for endpoints, request payloads and response codes, so write those first: what identifies the caller, what the limit response looks like, and what the client does after a 429. For the notification system, say how a retry avoids sending twice and what happens when email, SMS or push is down, before choosing any components. The design worked exercise in this guide practises the same retry and partial-failure reasoning.
Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.
Given a list of user session logs, find the most common sequence of pa…
Given a list of user session logs, find the most common sequence of pages visited by users within a specific time window.
Approach
- Name the brute-force solution and its complexity before improving on it.
- Restate the input: its shape, its size, and what is guaranteed about it.
- State the target complexity and say which constraint rules the naive version out.
Follow-up
- Which test case would catch an off-by-one here?
- What is the worst case, and how likely is it on real data?
Implement a custom data structure that supports insert, delete, and ra…
Implement a custom data structure that supports insert, delete, and random element retrieval operations in constant time.
Approach
- Name the brute-force solution and its complexity before improving on it.
- State the target complexity and say which constraint rules the naive version out.
- Choose the data structure from the access pattern, not from familiarity.
Follow-up
- Which test case would catch an off-by-one here?
- How does this change if the input no longer fits in memory?
Parse and verify a timestamped multi-signature webhook header
An inbound webhook carries a signature header of at most 1 KiB shaped t=<unix seconds>,v1=<64 hex chars>, with up to five v1 values during secret rotation and possibly unknown scheme keys. You hold the raw request body bytes and the currently active signing secrets. Write the parser and the verifier: accept when any active secret reproduces a signature and the timestamp is within a five-minute tolerance in either direction, reject otherwise. Single left-to-right pass over the header, no regular expression. State what is inside the MAC and why.
Approach
- Parse in one scan: split on
,, then on the first=only, since a value may itself contain=under a future scheme. Accepttexactly once and treat a secondtas a reject rather than last-wins. Push everyv1onto a short list and ignore any other key, so av2can be introduced later without breaking this verifier. - Say what is signed: HMAC-SHA256 over the exact byte string
<t>.<raw body bytes>, yielding 32 bytes or 64 hex characters. The timestamp sits inside the MAC because otherwise an attacker replays yesterday's body with its still-valid signature and only has to edit the header timestamp. - Hash the bytes as received. Verifying against a re-serialised JSON body is the usual defect: key order, whitespace and number formatting all change the bytes while the parsed objects compare equal, so signatures fail for honest senders and the popular 'fix' is to stop checking.
- Compare in constant time over fixed-length digests. Decode the hex to 32 bytes, accumulate
acc |= a[i] ^ b[i]across the whole length, and testacc == 0at the end. Evaluate every candidate without an early exit; at five candidates that is five HMACs over the body, linear in body size and negligible beside the network. - Apply the tolerance as a two-sided bound, rejecting when
|now - t| > 300seconds. A sender whose clock runs ahead of yours is an ordinary case, and an unbounded future timestamp is a free replay window. - Complexity: O(L) over the header producing k candidates, plus k HMACs at O(|body|) each. Space is O(k) beyond the body itself. Do the cheap rejections, including the tolerance check, before any cryptography runs.
Worked solution 15 min
- Write the grammar on one line before coding:
header := field (',' field)*,field := key '=' value, split on the first=only. - Implement the parser to return
{t: int, v1: [hex, ...]}, rejecting a missingt, a duplicatet, anyv1that is not 64 hex characters, and a header over 1 KiB, all before any cryptography runs. - Implement the verifier: for each active secret compute
HMAC-SHA256(secret, f'{t}.'.encode() + raw_body), compare it in constant time against each parsedv1, and OR the results with no early exit. - Test with a valid signature; the same body with
tmoved 400 seconds into the past; the same body witht400 seconds into the future; a header carrying an unknownv2=alongside a validv1; and a body re-serialised with different JSON key order.
Follow-up
- The body is 40 MB. What changes about where you verify, and what can you do before the whole body has arrived?
- A customer reports that signatures fail for exactly the requests whose body contains a non-ASCII character. What is your first hypothesis?
- How do you rotate the signing secret with no failed deliveries, and how long do both secrets stay live?
Enforce a concurrent-run quota that survives simultaneous requests
A plan allows at most 20 concurrently running rows in job_run per tenant. The table holds run_id, tenant_id, workspace_id, status (queued, leased, running, succeeded, failed, timed_out, cancelled, lost), lease_token, leased_until, started_at and finished_at. Today the service runs select count(*) from job_run where tenant_id = $1 and status = 'running', compares the result to 20, then inserts. Under load a tenant exceeds the cap by exactly the number of concurrent requests. Name the anomaly, say which isolation levels do and do not prevent it, and give a version that holds, as SQL.
Approach
- Name it: write skew. Each transaction reads a predicate (the count of running rows), neither modifies what the other read, and both then insert rows that jointly violate an invariant no single row expresses. Read committed permits it. So does repeatable read, because snapshot isolation's first-updater-wins check fires only on conflicting row updates, and these are inserts touching disjoint rows.
- Enumerate the fixes with their real costs. SERIALIZABLE works: PostgreSQL's SSI tracks the predicate read and aborts one transaction with SQLSTATE 40001, which obliges the caller to retry and makes the abort rate rise with contention on a hot tenant. Folding the predicate into the write as
insert ... select ... where (select count(*) ...) < 20narrows the race to the statement's snapshot but does not close it under read committed. - Give the version that holds at read committed: serialise on a row both transactions must touch.
update tenant_concurrency set running = running + 1 where tenant_id = $1 and running < 20 returning runningupdates zero rows when the cap is reached, and zero rows is the rejection. This works because at read committed a blocked UPDATE re-evaluates its WHERE clause against the newly committed row; at repeatable read the same statement raises a serialisation error instead, so the isolation level changes the calling contract. - State the cost you just bought. That row is now a per-tenant serialisation point, so admission throughput for the tenant is bounded by one divided by the lock hold time; at a 2 ms hold that is roughly 500 admissions/second. Keep the critical section to the single UPDATE, with no network call or scheduling decision inside the transaction, and decrement in the same transaction that writes the terminal status.
- Close the leak the status enum implies: a run can end as
lost, so a crashed worker otherwise consumes a slot forever. Reconcile on a schedule againststatus = 'running' and leased_until < now(), and treat the counter as a fast path overjob_run, which stays the system of record.
Follow-up
- Write the retry loop for the SERIALIZABLE version. What does the caller see when it keeps aborting, and what bounds the retries?
- Two regions each keep a counter. What is the effective cap, and what does admission do when the counter store is unreachable?
- The cap changes mid-flight on a plan upgrade. Do running jobs get killed, and what does the counter row look like during the change?
Model credential revocation so history survives the delete
tenant_api_key stores key_id, tenant_id, workspace_id, name, key_prefix, secret_hash, scopes text[], status (active, revoked, expired, compromised), auth_version, created_at, expires_at, last_used_at, revoked_at, revoked_reason. Rotation inserts a new row and revocation never deletes, because an incident review asks which credential served a request last quarter. Write the constraints that enforce: a label is unique only among a tenant's live keys, revoked_at and status can never disagree, and scopes is never empty. Then write the authentication lookup predicate, and name one column in this table that must stay out of it.
Approach
- Reach for a partial unique index rather than a plain UNIQUE:
create unique index on tenant_api_key (tenant_id, name) where revoked_at is null. Any number of revoked rows may share a label, the live namespace stays unique per tenant, and the revoked majority is not in the index at all, so it stays small on a table that only grows. - Tie the nullable timestamp to the enum so the two cannot drift:
check ((revoked_at is not null) = (status in ('revoked','compromised')))andcheck ((revoked_at is null) = (revoked_reason is null)). A revocation that records no reason is the one an incident review cannot use. - Write the emptiness check as
check (cardinality(scopes) > 0), notarray_length(scopes, 1) > 0. array_length returns NULL for an empty array, a CHECK constraint passes when its expression is NULL, so the array_length version accepts exactly the value it was written to reject. - Make the lookup a single index probe with every liveness condition inside it:
where secret_hash = $1 and revoked_at is null and (expires_at is null or expires_at > now()) and auth_version = $2, backed by a unique index on secret_hash. Nothing is filtered in application code, so there is no path that forgets a clause. - Keep last_used_at out of that predicate. It is written asynchronously and is allowed to lag by a minute, so it is a usage signal; feeding it into an authorisation decision makes the decision depend on a write that may be late, batched away or lost.
- Flag the modelling smell while you are here:
expiredis derivable fromexpires_at < now(), so storing it as a status obliges a job to keep it true and guarantees the column is wrong between the expiry instant and that job's next run. Derive it in the predicate; keep the stored status for states that are decisions rather than clock readings.
Worked solution 20 min
- Create the table with all three constraints on a scratch database and insert two revoked rows sharing (tenant_id, name); the partial index should accept both.
- Insert a second live row with that same name and confirm the violation names the partial index.
- Run
update tenant_api_key set revoked_at = now()leaving status = 'active' and confirm the CHECK rejects it; then tryinsert ... scopes = '{}'against both the cardinality and the array_length forms and note that only one rejects it. - Run
explain (analyze, buffers)on the lookup predicate for a live key and confirm an index scan on secret_hash with rows removed by filter equal to zero.
Follow-up
- Rotation issues a replacement while the old key stays live for a 30-day overlap. What does the uniqueness rule become, and what does the UI show to tell two same-named keys apart?
- A password reset bumps the principal's auth_version. No row in this table changed. How does the next request fail, and what query counts how many keys that bump just killed?
- A key turns up in a public repository. Which columns let you find it, and what do you write to the row?
Design a rate-limiting API, detailing the endpoints, request payloads,…
Design a rate-limiting API, detailing the endpoints, request payloads, and response codes.
Approach
- State how the contract changes without breaking existing clients.
- Say who the caller is and what they do when the call fails halfway.
- Design the error taxonomy before the success shape; callers branch on it.
Follow-up
- What happens if the caller retries after a timeout?
- How does a client discover it is on an old version of this contract?
Design a notification system that supports multiple delivery channels …
Design a notification system that supports multiple delivery channels (email, SMS, push) and ensures high availability and retry logic.
Approach
- State how the contract changes without breaking existing clients.
- Define the identity of a request so a retry cannot double-apply it.
- Separate accepted, pending, failed and confirmed; they are different facts.
Follow-up
- How does a client discover it is on an old version of this contract?
- What does a partial failure look like to the caller?
How would you structure a system to handle real-time code execution an…
How would you structure a system to handle real-time code execution and test case validation for thousands of concurrent users?
Approach
- Design the error taxonomy before the success shape; callers branch on it.
- State how the contract changes without breaking existing clients.
- Define the identity of a request so a retry cannot double-apply it.
Follow-up
- What does a partial failure look like to the caller?
- How does a client discover it is on an old version of this contract?
Refactor a legacy JavaScript function to improve its modularity, testa…
Refactor a legacy JavaScript function to improve its modularity, testability, and adherence to modern clean code standards.
Approach
- State your assumptions explicitly before working the problem.
- Work from the requirement backwards to the design.
- Clarify what is being asked and what a complete answer contains.
Follow-up
- What assumption would you test first?
- How would you know your answer was wrong?
Explain how memory allocation and garbage collection function in a lan…
Explain how memory allocation and garbage collection function in a language like Java.
Approach
- Work from the requirement backwards to the design.
- Clarify what is being asked and what a complete answer contains.
- State your assumptions explicitly before working the problem.
Follow-up
- How would you know your answer was wrong?
- What assumption would you test first?
Design the batch ingest endpoint metering agents retry into
A customer-run agent posts usage events in batches of up to 1,000 to metering-ingest with a 30-second timeout and at-least-once retry of the whole batch. Each event carries event_id, idempotency_key, sku, quantity and occurred_at; the server adds ingested_at, and usage_event is partitioned daily on ingested_at with unique (ingested_day, tenant_id, idempotency_key). Design the endpoint: the request shape, what the response says when 900 events are new, 90 are duplicates and 10 are malformed, the status code, and the agent's algorithm on timeout. Then state the deduplication horizon and justify it against that unique constraint.
Approach
- Fix the per-item outcome taxonomy first, because the status code follows from it: accepted, duplicate, and rejected with a permanent code. A duplicate is a success; reporting it as an error makes the agent either re-send revenue it already delivered or drop it.
- Allow only permanent failures per item. A transient per-item failure inside a 200 invites the agent to discard that event, so anything transient escalates to a 5xx for the entire batch. A 200 is then a promise that every event not marked rejected is committed and durable.
- Return 200 with a results array aligned by index and carrying the event id, so the agent can retry precisely the subset that needs it and quarantine the ten malformed events instead of hard-looping a poison batch forever. Cap the batch at 1,000 items and a byte size, with 413 beyond it and 429 with Retry-After for backpressure.
- Deduplicate per event, never per batch: the agent may split, merge or reorder a retried batch, so a batch-level key matches nothing on the second attempt. The key is (tenant_id, idempotency_key), and the tenant comes from the resolved credential; a tenant id present in the body is compared against it, never trusted.
- Size the horizon as a correctness parameter. The unique index includes the partition key, so it deduplicates only within one day: a retry that crosses midnight, or a replay run a week later, passes straight through it. A separate dedup store keyed (tenant_id, idempotency_key) with a TTL exceeding the agent's maximum retry window plus the longest replay you intend to support is what actually enforces the invariant, which makes its retention a correctness setting rather than a cost knob.
- Order the commit against the response and the acknowledgement: commit then respond at the endpoint, and downstream commit the fold then acknowledge the message. Acknowledging first turns a crash into silently lost revenue with no error raised anywhere.
Worked solution 40 min
- Write the request body schema with the batch envelope and one event, and state which fields the server assigns rather than accepts.
- Write the 200 response for the 900/90/10 case, showing three result entries, one of each outcome, with the rejected one carrying a permanent code.
- Write the rule separating per-item rejection from whole-batch failure, and list which conditions fall on each side.
- Compute the dedup horizon from the agent's retry window plus the replay window you support, and say where the dedup state lives and how it ages out.
- Write the agent's pseudocode for timeout, 5xx, 429 and 200-with-rejections, four branches, and mark which branch may drop an event.
- Trace the crash between commit and response, and between fold and acknowledgement, and say what each produces.
Follow-up
- The agent times out at 30 seconds having received nothing. What exactly does it do next, and what in your design makes that safe?
- Ten events are rejected every hour for a week and nobody notices. What does the endpoint owe the customer beyond a per-item 4xx code?
- A replay pushes 40 million events through this endpoint in an hour. Which part of your design degrades first?
Metering partition crash-loops and the sealing watermark freezes
One metering-ingest partition has stopped advancing. Lag grows linearly, the consumer restarts about every 40 seconds, and the same offset appears in every startup log while other partitions stay healthy. Events are committed in batches of a few thousand and the acknowledgement follows the commit. Sealing is six hours away and source_max_ingested_at for that partition's tenants is frozen. Give an ordered checklist, a containment action available within minutes, and the durable fix, saying what each does to exactly-once accounting.
Approach
- Distinguish a poison record from a capacity problem in one measurement: compare the offset and the exception across restarts. An identical pair every time is deterministic failure on one record, whereas a throughput problem still advances the offset between crashes.
- Read the record from a separate consumer group so the bytes can be inspected without perturbing the stuck consumer, then classify the defect: schema violation, a quantity failing the non-negative check, a null workspace, an unmappable SKU enum, or a payload past a size limit. That classification decides whether this is a producer bug or a missing consumer guard.
- Account for batch granularity before acting. With commits of a few thousand, one bad record fails thousands of good ones, so the blast radius is the batch. Halve the batch around the offset to isolate the record, or move to per-record error isolation so the radius becomes the record.
- Contain by diverting that record to a dead-letter store with its raw bytes and offset, then resume. This is safe here precisely because the acknowledgement follows the commit: the good records from the failed batch are re-consumed and absorbed by the uniqueness check on (tenant_id, idempotency_key) rather than counted twice.
- Make the fix durable with per-record error isolation, a bounded poison counter, and an alert on dead-letter rate rather than on lag alone, since lag only reveals this after the sealing margin has already been eaten.
- Check the horizon before replaying anything. The unique index lives on a daily-partitioned table and therefore includes the partition key, so it deduplicates within a day only; a replay landing on a later ingest day needs the separate dedup store or it double-counts into a tenant's bill.
Follow-up
- Move the acknowledgement before the commit and describe exactly what is lost and what is duplicated in each of the two crash windows.
- Sealing is in six hours and the partition will not drain in time. What do you seal on, and what does the invoice have to record so the difference is explainable later?
- A producer replays two weeks of events next month. Which part of your fix stops holding, and what is the dedup horizon you would actually configure?
Roughly ninety minutes on weeknights with one longer weekend block. The plan cuts scope rather than compressing everything, on the assumption that one thing finished per night beats four half-started.
Prepare, practise & reflect
One practical outcome each day. Spend longer where you need it.
0 / 7 done01Recruiter call prep and a cold coding baseline
- Mark each line of the posting as done, adjacent or new, and write which seat you are aiming at: Karat Studio product work, deployment and enterprise integrations, or community tooling.
- Write your recruiter questions: which seat this is, whether Karat Qualify comes first, which languages the Karat Studio IDE offers, whether lookups are allowed, and what the onsite rounds cover.
- Solve Path Existence in 2D Grid cold with BFS in a plain editor, then write one sentence on what slowed you down.
Deliverable: A marked-up posting, a recruiter question list, and one cold coding attempt with a note on what blocked it.
Practice prompt ↗Practice prompt ↗Practice prompt ↗Worked solution ↗02Karat Qualify: complexity and backend fundamentals
- Write the Big-O of array index and insert, hash map get and put, balanced BST search and insert, heap push and pop, comparison sort, and BFS/DFS over V vertices and E edges from memory, then check each one.
- Predict the output or complexity of ten short snippets in your main language before running them, and log every miss by topic.
- Refresh HTTP methods and status codes, index costs, and inner versus left joins, and practise joins with the bank question Join tables to map userId to name.
- Work the SQL worked exercise on credential revocation to rehearse constraint and index reasoning.
Deliverable: A one-page complexity and backend-fundamentals sheet, plus a log of the snippet predictions you got wrong.
Practice prompt ↗Practice prompt ↗03Karat Core: the CS fundamentals segment
- Write short spoken answers for the reported questions: BFS versus DFS complexity, balanced BST versus hash table search, Java memory allocation and garbage collection, and REST versus other protocols.
- Add the neighbouring topics: context switching and OS modes, threads and locks, stack versus heap, how a memory leak happens in a garbage-collected program, and what happens during an HTTPS request.
- Say each answer aloud, cut any that runs past a minute, and keep one concrete example per answer.
Deliverable: A fundamentals card with a short answer and one example for each topic, each rehearsed aloud.
Practice prompt ↗Practice prompt ↗04Karat Core: multi-part grid and data-structure coding
- Work the grid progression in one sitting: Neighbor Coordinates for Zeros, then Path Existence in 2D Grid, then 2D Grid String Search, reusing one neighbour helper throughout.
- Implement the insert, delete and getRandom structure with an array plus a map from value to index, deleting by swapping with the last element, and state why each operation is average O(1).
- Validate nested brackets with a stack, then try Calculator Parser With Variables as a stretch.
- Run tests after each helper and state the complexity before moving to the next part.
Deliverable: Three multi-part solutions built on shared helpers, each with complexity stated and tests run as you went.
Practice prompt ↗Practice prompt ↗Worked solution ↗05Parsing, logs and follow-up changes
- Do the coding worked exercise on parsing and verifying a multi-signature webhook header, which drills a single-pass parser and early rejection of bad input.
- Solve the session-log question: group logs by user, sort each group by time, and count page sequences inside the window with a hash map. Then say what changes when the input is large.
- Warm up on the bank's Validate password and list rule violations, and Implement obstacle-course run statistics, splitting each into helpers before coding.
Deliverable: The session-log solution and two parsing-style solutions, each with one follow-up you handled in writing.
Practice prompt ↗Practice prompt ↗06Design questions, code review and behavioural stories
- Write the rate-limiting API contract: endpoints, payloads, the 429 response with Retry-After, and where the counters live.
- Work the design worked exercise on the retry-safe batch ingest endpoint, then apply its retry and partial-failure reasoning to the reported notification-system and real-time code-execution questions.
- Review a piece of your own old code for style, security and testability, and refactor one function into testable pieces.
- Write four behavioural stories: unclear requirements, a project in trouble, a code review you led, and a performance decision.
Deliverable: One API contract, two design sketches with retry handling, a refactor with notes, and four stories.
Practice prompt ↗Practice prompt ↗07Full Core-format rehearsal and logistics
- Run a mock in the reported Core shape: a brief introduction, a short fundamentals quiz, then a multi-part coding problem in a plain editor with tests.
- Straight afterwards, write down where you lost time and fix only those moments.
- Confirm the logistics with your recruiter: language, lookup rules, and whether the redo option applies to you.
- Warm up only on a problem you have already solved from a blank file, and open no new material.
Deliverable: Mock notes naming where you lost time, plus a one-page card with fundamentals answers, your reusable helpers and the logistics.
Practice prompt ↗Practice prompt ↗Worked solution ↗Expand any day for tasks and deliverables. Your progress is saved on this device.
Candidates describe behavioural scenarios among the onsite rounds, and this role's question bank includes prompts on leading through unclear requirements, recovering a project in trouble, and explaining a practical code review. Prepare four or five stories that each name your own decision, the people involved and a result someone could check. Include at least one about working with product managers or designers, since the role description lists that collaboration as part of the job.
Ship metered billing with a named deduplication horizon
Metered billing must be on in three weeks. usage_event is partitioned daily, so its unique index must include the partition key and deduplicates only within a day: a producer retry that crosses midnight, or a replay run a week later, gets through. A cross-partition dedup store is two weeks you do not have. Describe shipping with debt you named in advance: what you shipped, what you wrote down, the detector you added, the trigger and date for paying it off, and what you would have refused to ship under the same pressure.
Approach
- Show you can separate the two kinds of debt, because that distinction is what the question actually probes. Debt that costs engineering time later is shippable on a deadline. Debt that silently corrupts a number a customer gets charged for is not shippable unless the corruption is detectable, and detectability is the whole negotiation.
- Make the exposure narrow and measured rather than gestural. The hole is duplicates whose occurrences straddle a UTC day boundary, plus any replay older than partition retention. Measure it before arguing about it: how often an idempotency_key recurs at all, and the distribution of the gap between first and last occurrence. If the ninety-ninth percentile of that gap is four minutes, the residual risk is a small band around midnight and you can say so numerically.
- Add the detector before the feature, not after. A nightly job counting keys that appear in more than one partition is one grouped scan over recent partitions, and it converts a silent overcount into a page. State what it costs to run and what it fires on.
- Buy the cheap half of the real fix immediately: extend partition retention so the dedup horizon exceeds the producer's maximum retry window plus the longest replay you intend to support. That reframes retention as a correctness parameter rather than a storage cost, which is the sentence you need on record before someone optimises the bill.
- Make repayment mechanical instead of aspirational: a dated entry with a named owner, plus a threshold that pulls the date forward — first detector hit above N events, or first customer dispute. Debt with a trigger gets paid; debt with only a date does not.
- Answer the second half honestly by naming what you would refuse under identical pressure: the sealing path, because a sealed row is frozen and a wrong number there stops being a bug and becomes an adjustment line, a dispute and an audit question.
Follow-up
- The detector fires on forty duplicate events for one tenant, and two of their invoices have already sealed. What happens next?
- Whom did you tell that the billing numbers had a known hole, and in what words?
- Finance asks you to cut storage by shortening partition retention. What do you say, and to whom?
Reverse a webhook ordering decision after measuring its cost
You argued for strict per-subscription ordering in webhook-delivery, which means one in-flight attempt per subscription. It shipped. Three months later a single unresponsive endpoint holds one subscription's queue at a six-hour backlog, and two customers report events arriving out of order anyway once their own retries are counted. Describe a decision you reversed: what you originally optimised for, the measurement that changed your mind, what the reversal cost in engineering time and customer change, and how you told the people who had already built on the original guarantee.
Approach
- State the original decision as a trade you made knowingly. Ordering across a network requires a single in-flight attempt per subscription, and its price is head-of-line blocking whenever one endpoint is slow. 'We priced it wrong' is a much stronger opening than 'we did not realise', and it is usually the true one.
- Bring the measurement that flipped it, not the anecdote: backlog age at the ninety-ninth percentile per subscription, the share of subscriptions where one slow endpoint gated an otherwise healthy queue, and the delivery throughput lost to serialisation. A reversal justified by complaints is indistinguishable from a reversal justified by fatigue.
- Name what you learned about the guarantee itself, which is the engineering content of this story. At-least-once delivery means a retried event already arrives after newer ones and the consumer already must be idempotent, so a guarantee the customer has to defend against anyway was never worth what it cost to provide.
- Describe the migration, because reversing a published contract is the hard half and the part candidates skip. Parallel attempts behind a per-subscription flag, a monotonically increasing sequence number added to the envelope so order-sensitive consumers can sort or discard, documentation that states at-least-once and unordered in those words, and a deprecation measured in quarters because the client is a pinned SDK inside a build pipeline you cannot see or redeploy.
- Give the cost in the two currencies that matter: engineer-weeks, and how many customers had to change code. Then say who you told before it shipped rather than in a changelog afterwards, and which large customer you left on the old behaviour and for how long.
- Close with the signal you now weight differently, stated as something you would do earlier next time: measuring the blocking cost on the slowest decile of endpoints before committing to the guarantee, rather than after a customer noticed.
Follow-up
- A customer insists they need ordering. What do you offer them that is not global serialisation?
- How did you choose the deprecation window given that you cannot see or redeploy the clients?
- What would have to be true for you to reverse back?
Estimate a tenant-leading index migration you have never run
Someone needs a date. usage_event carries an index on (occurred_at) and needs (tenant_id, occurred_at); the largest tenant holds roughly a hundred times the median tenant's rows, the table is partitioned daily with years of retention, and you have never run a migration on a table this large. Give an estimate you would defend: how you decompose the work, the two or three numbers you would go and measure first, the range and confidence you state, and what you commit to when the person asking needs a single date today.
Approach
- Refuse the bare number and then give one anyway, in the form that is actually useful: a range plus the measurement that collapses it. 'Four to eleven days; one afternoon building this index on a restored copy of the largest partition takes that to within a day' is an answer, while 'it depends' is not.
- Decompose by failure mode rather than into equal chunks, because that is where estimates go wrong. On a partitioned parent you create the index ON ONLY the parent, build each partition's index with CREATE INDEX CONCURRENTLY, then ALTER INDEX ... ATTACH PARTITION, at which point the parent index becomes valid. CONCURRENTLY does not block writes but scans each partition twice, waits out older transactions, cannot run inside a transaction block, and on failure leaves an invalid index you must drop concurrently and retry.
- Name the two unknowns that dominate and price them: build time on one restored partition of realistic size, and whether the planner actually chooses the new index for the skewed tenant, since selectivity for a tenant holding most of the rows is a different question from selectivity for the median tenant. Both are half-day measurements against a replica, and both are cheaper than being wrong by a week.
- State the assumptions the range is conditional on, because that is what makes a slip a re-estimate instead of a credibility event: no partition above a stated row count, one concurrent build at a time so it does not compete with ingest for I/O, and an ingest backlog that can absorb the added write amplification while both indexes exist.
- Budget the step nobody budgets: verification and the old index's removal. Dropping the old index is fast, but deciding it is safe to drop means confirming no plan still uses it, and that confirmation waits on real traffic across a full weekly cycle rather than on your patience.
- Answer the single-date request honestly. Commit to a date for the first checkpoint — the measured build number from the replica — and to re-estimating on that date, and say plainly what you are not committing to yet. A date with a scheduled re-estimate is worth more to the asker than a confident wrong one, and you should say why in those words.
Follow-up
- The concurrent build fails half way through the largest partition. What is the state of the database and what do you do next?
- Your estimate slips by sixty percent. Which assumption broke, and at what point would you have known?
- The person asking needs the date for a customer commitment. Does your answer change?
- 01
Tell me about a project where the requirements were unclear. How did you get enough clarity to start, what did you prioritise, and what did you change once you learned more?
- 02
Describe a project that hit a major obstacle. What was your part in recovering it, who outside engineering did you work with, and what would you do earlier next time?
- 03
Walk through a code review where you found a style, security or best-practice problem. How did you raise it, how was it fixed, and how did you confirm the fix?
- 04
Tell me about a time you had to decide whether code was fast enough. What did you measure, and what did you deliberately not optimise?
- 05
Describe a feature where the user experience and the technical constraints pulled in different directions. How did you and the product manager or designer settle it?
- 06
Tell me about a bug or a bad call that was yours. What check would have caught it, and does that check exist now?
Is this an official Karat interview guide?
No. It is PracHub's own research and practice material for the Software Engineer role at Karat. Rounds and questions reflect what candidates have reported, not a process Karat has published, and they change over time. Confirm the current format and scope with your recruiter.
PracHub interview research ↗How does the Karat redo option work?
Candidates describe a redo option for the Karat Core interview. If you feel the session did not reflect your ability, you can request a second attempt within 24 hours, with a different Interview Engineer and a new set of questions, and the hiring team considers your best attempt. Confirm the current policy with your recruiter, and still prepare as if the first attempt is the only one. The redo uses the same format, so write down what went wrong the first time and fix that before rebooking.
PracHub interview research ↗Why does the Karat Core interview feel scripted?
Candidates report that Karat Interview Engineers follow a standardized, structured protocol, so the session can feel formal. Use that predictability. Because the format repeats, you can rehearse the opening, the fundamentals quiz and the multi-part coding flow in advance. Do not read a neutral reaction as a bad sign. Keep narrating your approach, edge cases and complexity so your reasoning is visible.
PracHub interview research ↗How hard are the coding questions?
Candidate reports put the coding questions at roughly LeetCode Easy to Medium, and describe the coding portion as a sequence that starts easy and builds. The bank questions for this role range from easy grid problems, such as neighbour coordinates and BFS path existence, to harder ones, such as 2D grid string search with backtracking and a calculator parser with variables. Practise finishing the easy part fast rather than only solving hard problems slowly.
PracHub interview research ↗Can I use Google during the coding portion?
Candidate reports say you may look up basic syntax, library documentation or language APIs during the coding portion. Confirm the rule at the start of the session. Use it for a forgotten function name, not for an algorithm. Looking up an approach costs more time than it saves and leaves you explaining code you did not reason through.
PracHub interview research ↗What is the Karat Qualify round?
Candidates describe Karat Qualify as a 15-minute multiple-choice test on coding logic, algorithms and backend fundamentals, taken on your own. Passing it is reported to open scheduling for the Karat Core interview. To prepare, review standard complexities, predict the output of short code snippets without running them, and refresh backend basics such as HTTP methods, status codes and relational-database queries.
PracHub Software Engineer practice ↗Which CS fundamentals should I review for the quiz segment?
Start with the reported questions: BFS versus DFS time and space complexity, searching a balanced BST versus a hash table, memory allocation and garbage collection in Java, and REST versus other protocols. Then cover the other topics reported for this role: threads and locks, stack versus heap, how a memory leak happens in a garbage-collected program, what happens during an HTTPS request, and context switching and OS modes. Prepare an answer of two or three sentences for each, with one example.
PracHub Software Engineer practice ↗What does the onsite loop cover?
Candidates describe several rounds with internal Karat engineers and managers, covering system architecture, practical coding, collaborative code reviews and behavioural scenarios. The reports do not tie specific questions to the onsite, so prepare by category. For architecture, work through the reported design questions: a rate-limiting API with its endpoints, payloads and response codes, a multi-channel notification system with high availability and retries, and a real-time code-execution system. For code review, practise finding bugs, performance problems and security issues in real code and explaining each fix. Front-end review, such as React components, is reported for specialised roles.
PracHub Software Engineer practice ↗Sources & methodology 3 sources ↗
Official role evidence, timestamped platform data and clearly labeled preparation advice.
- 01PracHub interview research ↗
PracHub editorial research into this company and role, maintained with this guide. Candidate-reported, not an employer publication.
platform · Accessed 2026-09-24 - 02PracHub Software Engineer practice ↗
Cross-company practice questions for this role.
platform · Accessed 2026-09-24 - 03PracHub interview preparation framework ↗
The framework the preparation plan follows.
platform · Accessed 2026-09-24