TL;DR: The best full-stack interview follows one feature from the button to the database and back. These questions test that trace, the design calls behind it and the live exercises that expose gaps, with notes on what to probe after each answer.
TypeScript 7 shipped on July 8, 2026 as a native compiler, and Microsoft reports full builds 8 to 12 times faster than TypeScript 6. Next.js 16 made caching opt-in, and PostgreSQL 18 added uuidv7().
A full-stack hire now has to follow changes on every layer at once. The questions below test whether a candidate can connect those layers on one real feature.
- 1One end-to-end trace question reveals more than ten layer-by-layer definitions.
- 2Broken object-level authorization is item 1 on the OWASP API Security Top 10, and full-stack code is where it usually slips in.
- 3TypeScript 6.0 made
strict: truethe default, so older projects that relied on the loose default must now opt out explicitly. - 4Node.js now runs
.tsfiles directly by stripping types, but syntax such asenumstill fails without an extra flag.
This page is the assessment plan. For definitions such as SSR versus CSR or SQL versus NoSQL, use our full stack developer interview questions on core concepts.
Tracing a Request
1. Walk me through everything that happens between a user clicking "Place order" and seeing the confirmation.
A strong answer names each layer in order and says what can fail at each one. The browser disables the button and sends a POST. The request passes TLS and any CDN or proxy, and the server checks the session.
The handler validates input, checks ownership and prices the cart on the server. A database transaction creates the order and reserves stock. The response returns and the UI moves on.

Probe: "Where is the price calculated?" The only right answer is the server; a price sent from the browser can be edited. Then ask what happens if the confirmation email fails.
A good candidate moves the email to a queue so a mail outage cannot fail the order.
2. Where do you validate a signup form, and why more than once?
Validate in the browser for fast feedback, and again on the server because the browser can be skipped. The database enforces the last rules with constraints.
The strongest answers share one schema between client and server, for example a Zod or Valibot schema in a TypeScript codebase, so the rules cannot drift. Probe for the rule only the database can enforce: a unique email.
Two requests can both pass a "does this email exist?" check, and only a unique index stops the second insert.
3. A user saves a change, reloads, and sees the old value. Where do you look?
Check each cache between the user and the database, from the browser inward. A candidate who lists these without prompting has debugged this for real:
- A client data cache, such as TanStack Query or SWR, that was never invalidated after the save.
- A framework cache, such as a cached page or
"use cache"function in Next.js that needsrevalidateTag()orupdateTag(). - A CDN or browser cache honouring a long
Cache-Controlheader. - A read replica that lags behind the primary database.
- A save that silently failed, and a UI that showed an optimistic update anyway.
Probe: "How would you tell these apart in five minutes?" Look for response headers, a network tab check and a direct database query.
4. How does a login session travel from the login form to an authenticated API call?
The server creates a session and sets a cookie; the browser sends that cookie with every later request, and the server looks the session up. The cookie flags decide how safe that is.
HttpOnly: page scripts cannot read it, so an XSS bug cannot steal it.Secure: it is only sent over HTTPS.SameSite=LaxorStrict: it is not sent on most cross-site requests, which blocks most CSRF.
Probe the common mistake: storing a JWT in localStorage because a tutorial did. Any injected script can read it. See the Set-Cookie reference for each flag.
5. An alert says one endpoint's p95 latency tripled. What do you do in the first 15 minutes?
Find which layer got slower before changing anything. Check whether a deploy or a traffic change lines up with the start. Then open a trace for a slow request and see where the time goes: application code, database, or an outside API.
Strong candidates name their tools: distributed tracing such as OpenTelemetry, the slow query log, and EXPLAIN ANALYZE on the suspect query.
A sudden jump with no deploy often means a query plan changed or a table grew past a size where a missing index starts to hurt. Rolling back first and investigating second is a good answer when a deploy lines up.
Designing a Feature
6. Design comments with one level of replies: the table, the API and the UI.
One comments table with a nullable parent_id covers it. Index (post_id, created_at, id) for the list, and parent_id for the replies.
The API returns top-level comments with a cursor and a reply count, and loads replies on demand. The UI posts with an optimistic update and rolls back on error.
Probe the edges: who can delete a comment, what a deleted parent shows, and how the design changes if replies can nest forever.
7. Offset or cursor pagination for that comment list?
Cursor pagination for feeds that change while people read them; offset pagination is fine for small admin tables with page numbers.
- Jump to any page number
- The database still reads and skips the first 400 rows
- New rows shift pages, so items repeat or vanish
- Uses the index, so page 50 costs the same as page 1
- Stable while new rows arrive
- No "go to page 37"
SELECT id, body, created_at
FROM comments
WHERE post_id = $1
AND (created_at, id) < ($2, $3) -- the cursor from the last row
ORDER BY created_at DESC, id DESC
LIMIT 20;
The id breaks ties between rows with the same timestamp. Without it, rows can be skipped at a page boundary.
8. How do you make the "Pay" button safe to click twice?
Give each payment attempt an idempotency key and let the database reject a second use of it. Disabling the button helps, but a retry after a network timeout can still send the request again.
CREATE UNIQUE INDEX orders_idem ON orders (user_id, idempotency_key);
INSERT INTO orders (user_id, idempotency_key, total_cents)
VALUES ($1, $2, $3)
ON CONFLICT (user_id, idempotency_key) DO NOTHING
RETURNING id; -- no row back means it already exists: return that order
Payment providers work the same way. Stripe's idempotent requests accept a key of up to 255 characters and return the first result for a repeat. A candidate who has handled payments will pass the same key through to the provider.
9. How do you rename a database column without downtime?
Split it into steps that each work with the code before and after them: expand, migrate, contract. Renaming the column in one migration breaks every running server that still uses the old name.

Add the new column and write to both. Backfill old rows in small batches so the table is not locked for long. Switch reads to the new column. Only when nothing writes the old column, drop it.
Probe: "What if you need to roll back after step 2?" The old column still has current data, which is the point.
10. Which work belongs in the request, and which in a background job?
Keep in the request only what the user must see succeed: the order row, the payment result. Move the rest to a queue: emails, PDFs, webhooks, search indexing and thumbnails.
Probe the gap between them. If the job is queued before the transaction commits, a worker can run before the order exists. If it is queued after, a crash in between loses it.
The strong answer is a transactional outbox: write the job to a table in the same transaction, and let a worker send it.
11. Where should this page fetch its data: on the server, in an API route, or in the browser?
Fetch on the server when the data is needed for the first render or must stay private; fetch in the browser when it depends on user interaction after load.
With React Server Components, a server component can query the database directly, and no API route is needed for that page. A public API route still makes sense when a mobile app or a third party needs the same data.
Probe the security edge: server code that reads secrets must never be imported into a client component.
Live Exercises
12. "The cart total is wrong after removing an item. Here is the repo; find the bug." What do you watch for?
Watch how they search, not only whether they find it. A good candidate reproduces the bug first, then decides whether the wrong number comes from the API or from the UI.
Plant the bug where layers meet, such as a client that subtracts the item price while the server recalculates with a discount.
Strong candidates open the network tab early, compare the response with what the screen shows, and add a test that fails before they fix anything.
13. "Add a due date to tasks, end to end, in 60 minutes." What does a good result include?
A migration, validation on both sides, an API change that keeps old clients working, a UI field, and at least one test. Finishing all five in a small way beats a polished UI with no migration.
Probe the decisions they made without being asked. Is the column nullable so existing rows stay valid? Is the date stored in UTC or as a plain date? Does the API accept a missing value from older clients?
These choices show more than the code itself.
14. "Review this pull request." Which planted problems should a strong candidate catch?
Plant four problems, one per layer, and count how many they find unprompted:
- A query inside a loop that causes N+1 database calls.
- A handler that loads a record by ID without checking the owner.
- User text rendered as raw HTML, for example with
dangerouslySetInnerHTML. - A new filter column with no index.
Three of four is a strong result. Also note tone: review comments that explain the risk and suggest a fix are what the team will receive every day.
15. Here is an EXPLAIN ANALYZE output with a sequential scan. What would you change?
A sequential scan on a large table behind a selective filter usually means a missing index. Add an index that matches the filter and sort, then run EXPLAIN ANALYZE again to confirm the plan changed.
Strong candidates know when a sequential scan is fine: on a small table, or when the filter matches most rows. They also compare estimated rows with actual rows; a large gap means stale statistics, fixed with ANALYZE.
See the PostgreSQL guide to using EXPLAIN.
Security and Operations
16. How do you stop users from viewing other users' invoices by changing the ID in the URL?
Check ownership on every request, in the query itself. Hiding the link in the UI does nothing. Broken object-level authorization is the first item in the OWASP API Security Top 10 (2023).
SELECT * FROM invoices
WHERE id = $1 AND account_id = $2; -- $2 comes from the session, never the request
Return 404 rather than 403 for someone else's record, so the API does not confirm it exists. Random IDs such as UUIDs make guessing harder but are not a fix on their own.
17. Where do secrets live, and how can one leak to the browser by accident?
Secrets live in environment variables or a secret manager on the server, never in the repository. The accidental leak usually comes from a build tool that copies variables into the client bundle.
In Next.js, any variable prefixed NEXT_PUBLIC_ is inlined into the JavaScript sent to the browser at build time, per the environment variables guide. Vite does the same with VITE_.
18. A release with a database migration broke checkout. How do you roll back?
Roll back the application code first; if migrations follow expand and contract, the old code still works on the new schema. That is why destructive migrations ship separately and last.
Probe: "What if the migration dropped a column?" Then a code rollback is not enough and data may need restoring from backup. A strong candidate says they would never ship that drop in the same release as the code change.
Judgement and Ownership
19. How do you use AI coding assistants on a full-stack codebase, and how do you check their output?
Use them for drafts, boilerplate and tests, and review every change as if a new teammate wrote it. The risk is code that compiles and looks right but skips an authorization check or adds a query in a loop.
Listen for concrete habits: running the tests, reading the diff line by line, checking new dependencies, and never pasting secrets or customer data into a prompt. A candidate who cannot explain code they submitted should not ship it.
20. Tell me about a production incident you owned from start to finish.
A strong story covers detection, the first fix, the root cause and what changed afterwards, in that order. Listen for layers: did the fix touch only the symptom in the UI, or the cause in the API or the data?
Ask what alert would have caught it sooner. Candidates who added that alert, or a test, after the incident show ownership. Blaming another team without saying what they would do differently is a warning sign.
What Changed Recently
21. How did React 19 change the way a form saves data?
React 19 added Actions: a form's action can be an async function, and React tracks the pending state, errors and optimistic updates for it. The React 19 announcement introduces useActionState, useOptimistic and useFormStatus for this.
With Server Components, that action can be a Server Action, marked with "use server", that runs on the server, so a form can save without a hand-written API route. Probe: "Is a Server Action a public endpoint?" Yes.
It must check authentication and ownership like any API route. React 19.2 later added <Activity> and useEffectEvent.
22. What changed about caching and middleware in Next.js 16?
Caching became opt-in. Per the Next.js 16 announcement, dynamic code runs at request time by default, and you cache pages, components or functions explicitly with the "use cache" directive.
The same release replaced middleware.ts with proxy.ts to make the network boundary clearer, and made Turbopack the default bundler.
A candidate who upgraded should mention updateTag() and revalidateTag() for invalidation, and async params, one of the breaking changes.
23. What do TypeScript 6 and 7 change for a team's builds?
TypeScript 7 is a native port written in Go. The TypeScript 7 announcement reports full builds 8 to 12 times faster, for example 125.7 seconds down to 10.6 seconds on the VS Code codebase.
TypeScript 6.0 was the bridge release. Its announcement lists new defaults: strict is true, module is esnext, and target follows the latest ECMAScript year.
A project that relied on the old loose default must now set strict: false or fix the new errors.
24. Can Node.js run TypeScript without a build step now?
Yes, for code that only uses erasable type syntax. Node.js 23.6 turned on type stripping by default in January 2025, per its release notes, and node file.ts works on Node.js 22.18, 24 and 26.
Node.js removes the types; it does not type-check, so tsc still runs in CI. Syntax that generates code fails: we ran a file with an enum on Node.js 26.10 and it threw a syntax error.
The TypeScript docs page explains the --experimental-transform-types flag for that case.
25. What in PostgreSQL 18 matters to an application developer?
Three things: uuidv7(), virtual generated columns, and faster reads from the new asynchronous I/O system. The PostgreSQL 18 release notes report up to 3 times faster reads from storage in tests.
UUIDv7 values start with a timestamp, so new rows land at the end of a B-tree index instead of at random pages. That keeps inserts fast with UUID primary keys. Virtual generated columns compute a value at query time instead of storing it.
PostgreSQL 18.6 is the current minor release.
Signs of a Strong Answer
- They follow a feature through every layer without being prompted, and name what fails at each one.
- They put prices, permissions and uniqueness on the server and in the database, never only in the UI.
- They plan migrations that the old code can survive, and ship destructive steps last.
- They reach for traces, response headers and
EXPLAIN ANALYZEbefore guessing. - They treat Server Actions and API routes as public endpoints that need authorization.
- They know which recent defaults changed in their own stack, such as opt-in caching in Next.js 16 or strict mode in TypeScript 6.
Hiring Full-Stack Developers
A good loop uses one trace question, one design question and one live exercise, which fits in two hours. Second Talent matches companies with pre-vetted full-stack developers from Asia, screened with exercises like these.
See typical rates on our full-stack developer cost page.
Tell us the stack and we send a shortlist within 24 hours. Start hiring, or go deeper with our PostgreSQL and React interview guides.






