Full Stack Developer
Full Stack Developer Roadmap and Interview Guide
This page is a complete roadmap for becoming a full stack developer and passing the interviews. It starts with how the web works and plain HTML, CSS and JavaScript, then builds up a React and TypeScript front end, a Node.js back end, PostgreSQL and Redis, authentication and security, testing, Docker, CI/CD and the core AWS services, and ends with scaling, operations and interview preparation. Every topic is explained here; where a subject has its own skill roadmap, we summarise it and link to it.
It suits beginners who want to build whole products, front end developers adding the server side, back end developers who want to own the UI, and anyone preparing for full stack interviews. The second half is an interview guide: the rounds you will face, real questions with strong answers, portfolio projects and a ten-week preparation plan.
- Level
- Beginner to job-ready
- Time
- 9–15 months from zero at about 10–15 hours a week; 8–10 weeks of focused interview preparation if you already build full stack apps
- Scope
- 56 topics in 10 stages
- Before you start
- Comfort using a computer, a text editor and a terminal; No programming experience needed; the roadmap starts with HTML, CSS and JavaScript; A laptop that can run Node.js, Docker and a local PostgreSQL database
What you will be able to do
- Build a typed React front end and a Node.js REST API that share validation and types
- Model data in PostgreSQL, write efficient SQL, and use transactions, indexes and Redis caching correctly
- Implement secure sign-in, authorisation checks and defences against injection, XSS and CSRF
- Test the front end, API and database at the right levels and keep CI green
- Ship with Docker, GitHub Actions and core AWS services, with infrastructure described in Terraform
- Diagnose slow pages and endpoints and explain how to scale and monitor an app
- Pass coding, practical build, system design and behavioural interview rounds
What a Full Stack Developer does
A full stack developer builds features from the database to the screen. For one feature they might design the tables, write the migration, build the API endpoint with validation and permission checks, create the React screens and forms, write tests at each level and ship it through the deployment pipeline. Because they understand every layer, they can trace a bug or a slow page from the browser through the API to the query that causes it.
Full stack roles are common in startups and small teams, where one person needs to deliver whole features, and in product teams at larger companies that prefer engineers who can work across the boundary. Most full stack developers are stronger on one side; the job asks for real depth in one area and solid working knowledge of the rest, not expert level everywhere.
A typical week
- Turn a product requirement into a plan covering schema changes, API endpoints and UI screens
- Build React components and forms connected to your own APIs
- Write and review SQL, migrations and API handlers with validation and permission checks
- Write unit, integration and end-to-end tests, and fix failing CI pipelines
- Deploy changes, watch logs, metrics and error reports, and fix production issues
- Review teammates' pull requests across front end and back end code
- Discuss trade-offs with product managers and designers, and estimate work
What is expected at each level
Junior
- Builds well-scoped features across UI and API with guidance and review
- Writes correct SQL and API handlers with validation, and React components with tests
- Uses Git, pull requests and the team's deployment pipeline confidently
- Asks for help early and learns from code review
Mid
- Owns features end to end, from schema design to release and monitoring
- Spots security, performance and data integrity problems in their own and others' code
- Chooses sensible patterns for state, caching, background jobs and API design
- Handles production issues calmly and mentors juniors
Senior
- Designs the architecture for a product area, including data model, APIs and rendering strategy
- Leads technical decisions on infrastructure, testing and reliability with clear trade-offs
- Breaks large projects into safe, incremental releases and coordinates across teams
- Raises the team's standards through reviews, documentation and mentoring
Staff or Lead
- Sets technical direction across several teams or the whole product
- Leads migrations such as moving to a new framework, database or cloud setup with low risk
- Builds the platforms and practices that make other engineers faster and safer
The interview loop
- Recruiter screen20–30 min
What it tests. Your background, which side of the stack you are stronger on, the technologies you use, and expectations on level, salary and location.
How to prepare. Prepare a two-minute summary and one project story that covers database, API and UI. Read the job post and note the stack.
- Technical screen45–60 min
What it tests. A short coding task plus questions on JavaScript, HTTP, REST, SQL and React. Interviewers check fundamentals across the stack.
How to prepare. Revise async JavaScript, HTTP status codes, REST design, joins and indexes, and React hooks. Practise explaining answers in two or three sentences.
- Coding round (algorithms)45–60 min
What it tests. Easy to medium data structures and algorithms problems, with attention to complexity, edge cases and clean code.
How to prepare. Practise arrays, strings, hash maps, two pointers, stacks, trees and recursion in coding practice, two problems a day.
- Practical full stack build or take-home90 min live, or 3–4 hours take-home
What it tests. Building or extending a small app: an API endpoint with validation and a database query, plus a React screen that uses it. Code structure, tests, error handling and how you explain trade-offs.
How to prepare. Have a starter template you know well. Practise building a CRUD feature with pagination, validation and tests from scratch in under 90 minutes. Write a short README for take-homes.
- System design45–60 min
What it tests. Designing a product end to end: requirements, API, data model, architecture, scaling, caching and failure handling, plus key UI considerations.
How to prepare. Practise five classic prompts, such as a URL shortener, booking system, chat app, file sharing and a job board, in system design practice with a timer.
- Behavioural and hiring manager45 min
What it tests. Ownership, collaboration with product and design, handling incidents and disagreements, and how you prioritise.
How to prepare. Write six to eight stories in situation, task, action, result form: a feature you owned end to end, an incident, a disagreement, a mistake, a performance win and mentoring.
Skill roadmaps for this role
Each skill below has its own complete roadmap. Learn the core ones first.
- CoreGit and GitHub Roadmap
All team work flows through Git, pull requests and GitHub Actions pipelines.
- CoreJavaScript Roadmap
JavaScript runs on both sides of the stack and its async model is tested in most interviews.
- CoreTypeScript Roadmap
TypeScript lets you share types between database, API and UI, and most job posts expect it.
- CoreReact Roadmap
React is the most common front end library in full stack roles.
- CoreNode.js Roadmap
Node.js lets you write the API and background jobs in the same language as the front end.
- CoreSQL Roadmap
Almost every product stores its core data in a relational database, and SQL questions appear in many interviews.
- CoreAPI Design Roadmap
Full stack developers design the contract between their own front end and back end, and often for other clients too.
- HelpfulNext.js Roadmap
Next.js combines React UI and server logic in one framework, a common full stack choice.
- HelpfulDocker Roadmap
Docker gives consistent local environments and is the usual way to package apps for deployment.
The Full Stack Developer roadmap
- Stage 1Web and programming foundationsBeginner · 4–5 weeks · 7 topics
- Stage 2Front end with TypeScript and ReactBeginner · 5–6 weeks · 5 topics
- Stage 3Back end with Node.jsIntermediate · 5–6 weeks · 6 topics
- Stage 4Databases and SQLIntermediate · 4–5 weeks · 7 topics
- Stage 5Authentication, authorisation and securityIntermediate · 3 weeks · 5 topics
- Stage 6Full stack frameworks and architectureIntermediate · 3–4 weeks · 5 topics
- Stage 7Testing and code qualityIntermediate · 2 weeks · 4 topics
- Stage 8Deployment, cloud and infrastructureAdvanced · 5–6 weeks · 8 topics
- Stage 9Performance, scaling and operationsAdvanced · 3 weeks · 5 topics
- Stage 10Interview readiness and AI-assisted workAdvanced · 3–4 weeks · 4 topics
Stage 1 Web and programming foundations
Goal. Build static pages with HTML and CSS, write working JavaScript, use the command line and keep code in Git.
How the web works Core
Every feature you build crosses the network. A browser resolves a domain to an IP address through DNS, opens a TCP connection, sets up TLS for HTTPS, and sends an HTTP request with a method, path, headers and maybe a body. The server returns a status code, headers and a body. Learn the methods (GET, POST, PUT, PATCH, DELETE), the status classes (2xx, 3xx, 4xx, 5xx), and the headers you will meet daily: Content-Type, Authorization, Cookie, Set-Cookie and Cache-Control.
A full stack developer sees both ends of every request, so this model is how you debug: is the bug in the browser, the network, the API or the database?
Practice. Use the browser network panel and curl to make the same API request, and compare the headers each sends.
HTML Core
HTML gives a page its structure and meaning. Use semantic elements: header, nav, main, article, footer, headings in order, lists, and table for tabular data. Use button for actions and links for navigation. Forms need labels tied to inputs, the right input types and autocomplete attributes.
Good HTML gives you accessibility and search visibility for free and makes your React components simpler, because each element already has the right behaviour. Many full stack developers neglect this layer; interviewers notice when a candidate builds a clickable div.
Practice. Build a three-page static site with a contact form using only semantic HTML, and navigate it by keyboard.
CSS and Tailwind CSS Core
Learn the box model, the cascade and specificity, Flexbox for one-direction layouts and Grid for two-dimensional ones, and responsive design with mobile-first media queries and relative units. Custom properties hold colours and spacing so themes are easy to change.
Tailwind CSS is a utility-first framework that many full stack teams use because it is fast to work with and keeps styles next to markup. Each class maps to one or two CSS declarations, such as flex, gap-4 or md:grid-cols-2. Learn plain CSS first so you understand what the utilities do, then use Tailwind to move quickly. The CSS Roadmap goes deeper into layout and the cascade.
Practice. Build a responsive pricing page twice, once in plain CSS and once in Tailwind CSS, and compare the result.
JavaScript Core
JavaScript runs in the browser and, through Node.js, on the server, which is why it is the most common full stack language. Learn values and types, let and const, functions and arrow functions, objects and arrays, destructuring and spread, modules with import and export, and the array methods map, filter, reduce and find.
Then learn closures, the meaning of this, classes, error handling with try and catch, and the DOM: selecting elements, handling events and updating content safely with textContent. The JavaScript Roadmap covers the language in depth.
Practice. Build an interactive to-do list in plain JavaScript that saves items to localStorage.
Asynchronous code and the event loop Core
Both browsers and Node.js run JavaScript on a single main thread. Slow work such as network calls, timers and file reads happens outside it, and callbacks are queued to run later. The event loop runs one task at a time and drains the microtask queue (promise callbacks) after each task.
Write async code with promises and async/await. Run independent requests in parallel with Promise.all instead of awaiting them one by one, handle rejections, and add timeouts and cancellation with AbortController. On the server the same rule applies: never block the thread with heavy synchronous work, or every user waits.
Practice. Write a script that calls three APIs in parallel with a timeout and logs which ones failed.
Git and GitHub Core
Git tracks every change to your code. Learn to commit small, focused changes with clear messages, create branches, merge and rebase, resolve conflicts, undo mistakes with revert and restore, and inspect history with log and blame.
GitHub hosts repositories and adds pull requests, code review, issues and GitHub Actions for automation. Most teams work on short-lived branches merged through reviewed pull requests with required checks. Your GitHub profile is part of your application, so keep projects tidy with clear READMEs. The Git and GitHub Roadmap covers branching strategies and advanced Git.
Practice. Contribute a small fix to a friend's repository through a fork, a branch and a pull request.
Linux / Unix and the command line Core
Servers almost always run Linux, and full stack developers touch them for deployment, debugging and scripting. Learn to move around the file system, read and edit files, use pipes and redirection, search with grep and find, and check processes, ports and disk with ps, top, ss and df.
Understand users, groups and file permissions, environment variables, package managers such as apt, SSH with key pairs, and how services are started and restarted with systemd. Being comfortable in a Linux/Unix shell makes everything later, from Docker to cloud servers, much easier.
Practice. Set up a small Linux virtual machine, log in over SSH with a key, and find which process is listening on port 80.
Stage 2 Front end with TypeScript and React
Goal. Build a typed React app that fetches data, handles forms and routes, and works well on any screen.
npm and front end tooling Core
npm installs packages from the registry and runs scripts defined in package.json. Learn dependencies versus devDependencies, semantic version ranges, and why the lock file must be committed. pnpm and Yarn are alternatives with the same ideas.
Modern projects use Vite or a framework's own tooling to run a dev server with hot reloading and to build optimised bundles. Add ESLint to catch bugs and Prettier or Biome to format code automatically, and run both in CI. Before adding a package, check its size, maintenance and licence, because every dependency is code you now ship and must keep updated.
Practice. Create a Vite React project with ESLint and Prettier configured, and add an npm script that runs both.
TypeScript Core
TypeScript adds static types to JavaScript and is now standard in full stack work. Its biggest benefit for full stack developers is sharing types across the boundary: the same Order type describes the database row, the API response and the React props, so a change in one place surfaces errors everywhere.
Learn type annotations, interfaces and type aliases, unions and narrowing, generics, and utility types such as Partial and Pick. Turn on strict. Types disappear at runtime, so validate incoming data at the edges with a schema library such as Zod and infer types from the schema. The TypeScript Roadmap covers advanced types.
Practice. Define a Zod schema for an API payload, infer its TypeScript type and use it on both client and server.
React Core
React builds interfaces from components: functions that take props and return JSX. Learn useState for local state, useEffect for syncing with outside systems, useRef, useContext, and useMemo and useCallback for caching. Lists need stable keys. Prefer deriving values during render to copying them into state.
Think in components: split a screen into small pieces with clear props, lift shared state to the nearest common parent, and compose with children. Most full stack interviews include building or extending a small React feature, so practise until the basics are automatic. The React Roadmap covers hooks and patterns in depth.
Practice. Build a filterable, sortable table of products from a JSON file using only derived state.
Data fetching and state on the client Core
Every screen that loads data has four states: loading, empty, error and success; handle each one. Data from the server is best managed with a server-state library such as TanStack Query or SWR, which caches responses, deduplicates requests, refetches stale data and makes invalidation after a mutation simple.
Keep other state where it belongs: local state in components, filters and pagination in the URL, and only truly global values such as the current user in context or a small store. Optimistic updates show a change immediately and roll back if the server rejects it, which makes apps feel fast.
Practice. Build a comments list that loads with TanStack Query and adds comments optimistically with rollback on error.
Routing, forms and accessible UI Core
Single-page apps change views by updating the URL with client-side routing, for example with React Router; meta-frameworks such as Next.js use file-based routes. Learn nested layouts, route parameters, protected routes and lazy loading.
Forms are the heart of most business apps. Use labelled inputs, clear inline errors, schema validation shared with the server, and protection against double submission. A form library such as React Hook Form keeps large forms fast. Make every control keyboard accessible with visible focus, enough colour contrast and responsive layouts that work on a phone.
Practice. Build a sign-up and profile-edit flow with shared validation, routing between pages and full keyboard support.
Stage 3 Back end with Node.js
Goal. Build a REST API in Node.js with validation, error handling, background jobs and email.
Node.js Core
Node.js runs JavaScript outside the browser using the V8 engine and an event loop backed by libuv. It handles many concurrent connections well because I/O is non-blocking, which suits APIs that mostly wait on databases and other services. It is a poor fit for heavy CPU work on the main thread; move that to worker threads, a queue or another service.
Learn the module system (ES modules and CommonJS), the built-in modules for files, paths, streams and HTTP, environment variables through process.env, and how to handle errors so one bad request cannot crash the process. The Node.js Roadmap covers the runtime in depth.
Practice. Write a Node.js script that streams a large CSV file line by line and counts rows without loading it into memory.
HTTP servers and frameworks Core
You can build a server with the built-in http module, but teams use frameworks. Express is the long-standing minimal choice with a huge middleware ecosystem. Fastify is faster and has schema-based validation built in. NestJS adds structure with modules, controllers and dependency injection, popular in larger teams. Hono is small and runs on Node.js, Bun and edge runtimes.
The core ideas are the same: routes map methods and paths to handlers, middleware runs before handlers for logging, authentication and parsing, and errors flow to a central handler. Structure code in layers (routes, services, data access) so business logic does not depend on the framework.
Practice. Build the same small API in Express and Fastify, each with logging middleware and a central error handler.
REST API design Core
REST models your API as resources addressed by URLs and manipulated with HTTP methods. Use plural nouns (/orders, /orders/42), the right methods, and accurate status codes: 201 for created, 204 for no content, 400 for invalid input, 401 for unauthenticated, 403 for forbidden, 404, 409 for conflicts and 422 for validation failures where your team uses it.
Design for clients: consistent JSON shapes, a standard error format, cursor pagination for long lists, filtering and sorting through query parameters, idempotency keys for payments and retries, and versioning when breaking changes are unavoidable. Document the API with OpenAPI. The API Design Roadmap covers this in depth.
Practice. Write an OpenAPI description for a small blog API, then implement it and check responses against the spec.
Validation and error handling Core
Never trust input. Validate every request body, query string and header at the edge of your API with a schema, and return clear 4xx errors that say which field is wrong. Normalise data (trim strings, parse dates) once, at the boundary.
Separate expected errors, such as "email already taken", from unexpected ones, such as a database outage. Expected errors map to specific status codes and messages. Unexpected errors return a generic 500 to the client while the full details, including a request ID, go to your logs. Never leak stack traces or SQL errors to users, because they reveal internals to attackers.
Practice. Add schema validation and a central error handler to your API that returns a consistent JSON error shape.
Background jobs, queues and scheduled tasks Recommended
Some work should not happen inside an HTTP request: sending emails, resizing images, generating reports or calling slow third-party services. Put it on a queue and let a worker process handle it. In Node.js, BullMQ on Redis is a common choice; cloud queues such as Amazon SQS work the same way.
Design jobs to be idempotent, because they may run more than once. Add retries with backoff, a dead-letter queue for jobs that keep failing, and monitoring of queue length. Scheduled tasks, such as nightly clean-ups, can use cron-style schedulers, but make sure only one instance runs each job.
Practice. Move sending a welcome email out of the sign-up request into a queued job with three retries.
Real-time features: WebSockets and server-sent events Recommended
Chat, notifications, live dashboards and collaborative editing need the server to push data. WebSockets give a two-way, long-lived connection. Server-sent events stream one-way updates over plain HTTP and reconnect automatically, which is simpler when only the server sends. Polling still works for low-frequency updates.
Real-time features complicate scaling: each server only knows its own connections, so use a shared channel such as Redis pub/sub to broadcast between instances. Authenticate connections, handle reconnects and missed messages, and limit how much each client can send.
Practice. Add live notifications to an app with server-sent events, and make them work across two server instances using Redis.
Stage 4 Databases and SQL
Goal. Model data in PostgreSQL, write efficient SQL, use transactions and indexes correctly, and cache with Redis.
Relational data modelling Core
Most full stack apps store their core data in a relational database. Model entities as tables with a primary key, connect them with foreign keys, and choose the right relationship: one-to-many (a user has many orders) or many-to-many through a join table (orders and products through order items). Normalise to avoid storing the same fact twice, then denormalise deliberately where reads need it.
Use constraints to protect data: NOT NULL, UNIQUE, CHECK and foreign keys. The database is the last line of defence when application code has a bug. Draw an entity diagram before writing code; interviewers often start a design round this way.
Practice. Design the schema for a course platform with users, courses, lessons and enrolments, including all constraints.
SQL Core
SQL is how you read and change relational data. Learn SELECT with WHERE, ORDER BY and LIMIT; joins (inner, left and when each drops rows); GROUP BY with aggregates and HAVING; subqueries and common table expressions; window functions such as ROW_NUMBER; and INSERT, UPDATE, DELETE and upserts.
Always use parameterised queries, never string concatenation, to prevent SQL injection. Watch for NULL behaviour and join fan-out that duplicates rows. Full stack interviews regularly include a SQL question, such as "top three customers by spend this month". The SQL Roadmap covers the language in depth.
Practice. Write ten queries against your course schema, including one with a window function and one with a CTE.
PostgreSQL Core
PostgreSQL is the most common open-source relational database for new products. Beyond standard SQL it offers JSONB columns for semi-structured data, full-text search, arrays, generated columns, row-level security and many extensions.
Learn the operational basics: indexes (B-tree by default, GIN for JSONB and full-text), reading EXPLAIN ANALYZE output to see whether a query uses an index, transactions and isolation levels, and connection pooling, because each connection uses server memory. Serverless functions can exhaust connections quickly, so use a pooler such as PgBouncer or a provider's pooled endpoint. Back up regularly and test restores.
Practice. Load a million rows into PostgreSQL, time a filtered query, add the right index and compare EXPLAIN ANALYZE before and after.
Transactions, indexes and concurrency Core
A transaction groups statements so they all succeed or all fail. ACID describes the guarantees: atomicity, consistency, isolation and durability. Concurrency bugs appear when two requests read and write the same data at once, such as two users booking the last seat. Fix them with a unique constraint, a conditional update (UPDATE ... WHERE seats_left > 0), row locks with SELECT ... FOR UPDATE, or a stricter isolation level.
Indexes speed up reads but slow writes and use space. A composite index on (user_id, created_at) helps queries filtering by user and sorting by date, but not queries filtering only by date. Index the columns your real queries filter and join on.
Practice. Simulate two concurrent bookings for the last seat and prevent overselling with a conditional update.
ORMs, query builders and migrations Core
Most Node.js teams access the database through a library. ORMs such as Prisma generate a typed client from a schema file. Drizzle and Kysely are type-safe query builders that stay close to SQL. TypeORM and Sequelize are older ORMs you will still find in existing code. Whatever you use, learn to read the SQL it generates.
The N+1 problem is the classic ORM mistake: loading a list, then running one query per item for related data. Fix it with joins or batched loading. Schema changes go through migrations, versioned files committed with the code and applied automatically in deployment. Make migrations backwards compatible so old and new code can run during a release.
Practice. Find and fix an N+1 query in an ORM-based endpoint, and measure the query count before and after.
Redis Core
Redis is an in-memory data store used for caching, sessions, rate limiting, queues, leaderboards and pub/sub. Its data types include strings, hashes, lists, sets, sorted sets and streams, and keys can expire automatically.
The most common pattern is cache-aside: read from Redis, and on a miss read from the database and store the result with a time-to-live. The hard part is invalidation: delete or update the cached value when the data changes, and protect against stampedes, where many requests miss at once and overload the database. Redis is not a primary store for data you cannot lose unless configured carefully for persistence.
Practice. Add cache-aside caching with a TTL to a slow endpoint, invalidate it on update, and add a Redis-based rate limiter.
NoSQL and choosing a database Optional
Document databases such as MongoDB store JSON-like documents with flexible schemas, which suits data that varies per record or is read as a whole. Key-value stores, wide-column stores and search engines such as Elasticsearch solve other specific problems. Vector databases, or the pgvector extension in PostgreSQL, store embeddings for AI search features.
For most full stack products, start with PostgreSQL: it handles relational data, JSON and full-text search well. Add a specialised store only when you have a clear need that PostgreSQL cannot meet. Be ready to explain this reasoning in interviews.
Practice. Store the same product catalogue in PostgreSQL and MongoDB and write a short comparison of queries and constraints.
Stage 5 Authentication, authorisation and security
Goal. Add secure sign-in and permission checks, and defend a full stack app against the common attacks.
Sessions, cookies and JWT Core
There are two main ways to remember a signed-in user. Server sessions store state on the server (often in Redis) and give the browser a random session ID in a cookie. They are easy to revoke. JWT (JSON Web Token) puts signed claims, such as the user ID and expiry, in a token the server can verify without a lookup. They suit stateless APIs and service-to-service calls but are hard to revoke before expiry.
For browser apps, keep the session ID or token in an HttpOnly, Secure, SameSite cookie so JavaScript cannot read it. If you use JWTs, keep access tokens short-lived, use refresh tokens with rotation, verify the signature and algorithm, and never put secrets in the payload, which is only encoded, not encrypted.
Practice. Implement login twice, with Redis sessions and with short-lived JWTs plus refresh tokens, and compare logout behaviour.
Passwords, OAuth and sign-in options Core
If you store passwords, hash them with a slow, salted algorithm designed for passwords, such as Argon2id or bcrypt, never with plain SHA-256 or reversible encryption. Add rate limiting on login, account lockout or delays, secure password reset links that expire, and multi-factor authentication for sensitive actions.
Many apps avoid storing passwords altogether. OAuth 2.0 with OpenID Connect lets users sign in with Google, GitHub or a company identity provider, using the authorisation code flow with PKCE. Passkeys use public-key cryptography and resist phishing. Auth libraries and hosted identity services save a lot of work; understand what they do even if you do not build it yourself.
Practice. Add sign-in with GitHub through OpenID Connect or OAuth to an app, alongside email and password with Argon2id.
Authorisation and multi-tenancy Core
Authentication says who you are; authorisation says what you may do. Broken access control is one of the most common serious flaws: an API that returns /invoices/123 to any logged-in user, without checking the invoice belongs to them. Check ownership or permission on every request, on the server, in one consistent place.
With role-based access control, each role such as admin, editor or viewer carries a fixed set of permissions. Attribute-based rules add conditions such as team or region. In multi-tenant SaaS, every query must be scoped to the tenant; PostgreSQL row-level security can enforce this as a second layer. Write tests that try to access another user's data.
Practice. Add roles and per-tenant scoping to an API and write tests proving one tenant cannot read another's records.
Web security for full stack apps Core
Learn the main attacks and their defences. SQL injection: always use parameterised queries. Cross-site scripting: let the framework escape output, sanitise any HTML you render, and add a Content Security Policy. Cross-site request forgery: use SameSite cookies and CSRF tokens for cookie-authenticated forms. Server-side request forgery: never fetch arbitrary URLs supplied by users without an allow list.
CORS is a browser rule controlling which origins may read your API responses; configure it narrowly, and remember it does not protect your API from non-browser clients. Also apply rate limiting, security headers, dependency audits and the principle of least privilege for database users. The OWASP Top Ten is a good checklist.
Practice. Run a dependency audit and a security header scan on your app, and fix every high-severity finding.
Secrets and configuration Recommended
Configuration that changes between environments, such as database URLs, API keys and feature flags, belongs in environment variables or a secrets manager, never in the repository. Commit a .env.example with placeholder names, and add .env to .gitignore.
In production, use the platform's secret store or a service such as AWS Secrets Manager or Parameter Store, grant each service only the secrets it needs, and rotate keys regularly. Remember that anything sent to the browser is public: front end environment variables in Next.js or Vite are bundled into client code, so only expose values meant to be public.
Practice. Move all secrets in a project into environment variables, add secret scanning to CI and rotate one key.
Stage 6 Full stack frameworks and architecture
Goal. Build a full stack app with Next.js, choose rendering and API styles per feature, and structure code so it stays maintainable.
Next.js as a full stack framework Core
Next.js lets one codebase serve both the UI and the server logic. The App Router uses React Server Components, which run only on the server and can query the database directly; Client Components handle interactivity. Server Actions let a form call a server function without writing a separate API endpoint. Route handlers expose REST endpoints for mobile apps or third parties.
Learn where code runs, how to keep secrets out of client bundles, how caching and revalidation work, and how to handle loading and error states with layouts and Suspense. Many startups ship their whole product this way. The Next.js Roadmap covers the framework in depth.
Practice. Build a notes app in Next.js where a Server Component lists notes from PostgreSQL and a Server Action creates them.
Rendering strategies Core
Choose rendering per page. Client-side rendering builds the page in the browser, good for dashboards behind a login. Server-side rendering builds HTML per request, good for fresh, personalised or search-indexed pages. Static generation builds pages at deploy time, the fastest and cheapest option for content that rarely changes. Incremental regeneration refreshes static pages after a set time or on demand. Streaming sends the page shell first and fills in slow sections as data arrives.
Each choice moves cost between the browser, your servers and the CDN, and affects caching and SEO. Interviewers expect you to justify a choice for a given page.
Practice. Pick three pages of an app you know and write which rendering strategy each should use and why.
API styles: REST, GraphQL and RPC Recommended
REST is the default for public and general-purpose APIs because it is simple and works with HTTP caching. With GraphQL, the client names the fields it wants from a typed schema and gets them through one endpoint, which helps when many clients need different shapes of data; it adds complexity in caching, authorisation per field and query cost limits. RPC styles call named procedures: gRPC is common between back end services, and tRPC gives end-to-end types between a TypeScript server and client in the same repository.
Pick based on clients and team: a single web app in a monorepo might use tRPC or server actions, while a platform with partners needs a documented REST or GraphQL API.
Practice. Expose the same two operations through REST and tRPC, and compare the client code and type safety.
Project structure and monorepos Recommended
Full stack codebases grow quickly. Group code by feature rather than by technical type once the app is larger than a few screens, so everything about billing lives together. Keep business logic in plain functions or services that do not depend on the web framework, which makes them easy to test.
Monorepos hold the web app, API, shared types and UI library in one repository, managed with workspaces in npm, pnpm or Yarn and a build tool such as Turborepo or Nx that caches and runs tasks only for changed packages. Shared validation schemas and types are the main benefit for full stack teams.
Practice. Restructure a project into a pnpm workspace with web, api and shared packages, sharing one validation schema.
Architecture: monoliths, services and caching layers Recommended
Start with a well-structured monolith: one deployable app with clear internal modules. It is simpler to build, test, deploy and debug. Split out services only for clear reasons, such as very different scaling needs, separate teams or isolation of risky components. Microservices add network failures, distributed data and operational cost.
Know the layers where caching can happen: the browser, a CDN, the application (Redis or in memory) and the database's own cache. Each layer needs a plan for invalidation. Event-driven patterns, where services publish events to a queue, decouple work but make flows harder to trace.
Practice. Draw the architecture of an app you built, mark every cache layer and write how each is invalidated.
Stage 7 Testing and code quality
Goal. Test front end, API and database code at the right levels and keep the main branch green in CI.
Testing strategy Core
Tests let you change code safely. A good mix has many fast unit tests for pure logic, a solid set of integration tests that exercise an API endpoint against a real database or a React component with mocked network calls, and a few end-to-end tests of critical journeys such as sign-up and checkout. Types and linting are the cheapest layer of all.
Test behaviour, not implementation details, so refactors do not break tests. Make tests deterministic: control time, random values and network responses. A flaky test that sometimes fails is worse than none, because people learn to ignore failures.
Practice. Write a test plan for one feature listing which checks belong at unit, integration and end-to-end level.
Unit and integration tests Core
Vitest and Jest run JavaScript and TypeScript tests with assertions, mocks and coverage. For the API, start the app in a test and send real HTTP requests with a library such as Supertest, against a real PostgreSQL database started in Docker or with Testcontainers. Reset data between tests with transactions or truncation. This catches SQL, migration and validation bugs that mocks hide.
On the front end, Testing Library renders components and finds elements by role and label, the way users do. Mock the network at the request level with Mock Service Worker so components use their real fetching code.
Practice. Write integration tests for a create-and-list endpoint against a PostgreSQL container, covering validation errors.
End-to-end tests Core
End-to-end tests run a real browser against the running app and database. Playwright is the common choice: it supports Chromium, Firefox and WebKit, waits for elements automatically and records traces for debugging. Cypress is another popular option.
Keep the suite small and focused on the journeys that make money or would be disastrous to break. Seed data through APIs or the database, not through the UI. Run the tests in CI against a fresh environment or preview deployment for each pull request.
Practice. Write Playwright tests for sign-up, login and creating a record, and run them in CI against a seeded database.
Code review and quality gates Recommended
Every change on a team goes through a pull request. Keep pull requests small and focused, with a description of why, screenshots for UI changes and notes on how you tested. As a reviewer, check correctness, security, data migrations and naming before style, and phrase comments as questions or suggestions.
Automate what machines can check: formatting, linting, type checking, tests and dependency audits run on every pull request, and branch protection blocks merging until they pass. AI review tools can flag likely bugs early but do not replace a human who understands the product.
Practice. Review a classmate's or open-source pull request and leave five specific, kind comments.
Stage 8 Deployment, cloud and infrastructure
Goal. Package an app in Docker, deploy it through CI/CD to AWS, describe infrastructure as code and keep processes healthy.
Deployment basics and hosting options Core
Deployment turns code in Git into a running service. Platforms such as Vercel and Netlify build front ends and serverless functions from each push with preview URLs. Render, Railway and Fly.io run long-lived Node.js servers, workers and managed databases with little configuration. Cloud providers such as AWS give full control and more responsibility.
Whatever the platform, learn the essentials: separate environments (development, staging, production), environment variables, database migrations as part of the release, health checks, zero-downtime rollouts, and a fast rollback. Start on a platform, then learn AWS so you understand what the platform does for you.
Practice. Deploy a full stack app with a managed PostgreSQL database to a platform, with a staging and a production environment.
Docker Core
Docker packages an app and its dependencies into an image that runs the same way on a laptop, in CI and in production. A Dockerfile lists the steps to build the image; a container is a running instance of it. Docker Compose starts several containers together, such as your API, PostgreSQL and Redis, for local development.
FROM node:22-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-slim
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
USER node
CMD ["node", "dist/server.js"]Multi-stage builds keep images small, and running as a non-root user limits damage. The Docker Roadmap covers images, networking and volumes.
Practice. Write a Docker Compose file that runs your API, PostgreSQL and Redis together with one command.
Checkpoint — CI / CD with GitHub Actions Core
Continuous integration runs checks on every push; continuous delivery deploys every change that passes. GitHub Actions defines workflows in YAML files under .github/workflows: triggers such as push and pull_request, jobs that run on hosted runners, and steps that install dependencies, lint, type check, test, build a Docker image and deploy.
Treat this as a checkpoint in your learning: by now every project should build, test and deploy automatically. Cache dependencies to keep pipelines fast, store credentials as encrypted secrets or use OIDC to assume a cloud role without long-lived keys, and require a manual approval before production if your team needs one.
Practice. Create a GitHub Actions pipeline that tests every pull request and deploys main to staging automatically.
Basic AWS Services Core
AWS is the largest cloud provider and appears in many full stack job posts. You do not need all of it. Learn IAM first: users, roles and policies, and the rule of least privilege. Then the core building blocks: EC2 for virtual servers, S3 for file storage, VPC for private networking, Route53 for DNS, SES for sending email, RDS for managed PostgreSQL, CloudFront as a CDN, and Lambda for serverless functions.
Also learn the AWS CLI, how billing works and how to set a budget alert on day one, because forgotten resources cost real money. Other clouds such as Google Cloud and Azure have equivalent services with different names.
Practice. Create an AWS account with a budget alert, an IAM user with limited rights, and deploy a static site to S3 behind CloudFront.
EC2 and VPC Recommended
EC2 gives you virtual machines. You choose an instance type (CPU and memory), an operating system image and storage, and connect with SSH or AWS Systems Manager. Security groups act as firewalls that allow traffic only on chosen ports from chosen sources.
A VPC is your private network in AWS. It is split into subnets across availability zones: public subnets for load balancers, private subnets for app servers and databases with no direct internet access. Route tables, an internet gateway and a NAT gateway control traffic. A typical web app puts an Application Load Balancer in public subnets, EC2 instances or containers in private ones, and RDS in private database subnets.
Practice. Build a VPC with public and private subnets, run your API on EC2 in a private subnet behind a load balancer.
S3, Route53 and SES Recommended
S3 stores files as objects in buckets. Use it for user uploads, static assets and backups. Keep buckets private and give browsers presigned URLs to upload or download directly, so large files never pass through your API servers. Lifecycle rules move old files to cheaper storage or delete them.
Route53 is AWS's DNS service: point your domain at a load balancer or CloudFront distribution with alias records, and use health checks for failover. SES sends transactional email such as password resets and receipts. You must verify your domain, set up SPF, DKIM and DMARC records so mail is not marked as spam, and handle bounces and complaints.
Practice. Add direct-to-S3 uploads with presigned URLs to your app, and send a verification email through SES from your own domain.
Terraform and infrastructure as code Recommended
Clicking through a cloud console does not scale and cannot be reviewed. Infrastructure as code describes resources in files kept in Git. Terraform is the most widely used tool: you write HCL describing resources such as a VPC, an RDS database and an S3 bucket, then terraform plan shows what would change and terraform apply carries it out. State records what exists; store it remotely with locking so teammates do not overwrite each other.
Use modules to reuse patterns, separate state per environment, and review plans in pull requests like code. OpenTofu is an open-source fork with the same language; AWS CDK and Pulumi let you write infrastructure in TypeScript.
Practice. Describe your S3 bucket, CloudFront distribution and Route53 record in Terraform, then destroy and recreate them.
Ansible, Monit and running servers Optional
When you run your own servers rather than containers on a managed platform, you need to configure them repeatably and keep processes alive. Ansible is a configuration management tool: playbooks written in YAML describe packages, files, users and services, and Ansible applies them over SSH to many servers. Running a playbook twice should change nothing the second time.
Monit is a small utility that watches processes, ports, files and disk space, restarts a crashed service and sends alerts. Many teams now use systemd for restarts and a monitoring service for alerts instead, but you may still meet Monit on older Linux servers. Process managers such as PM2 keep Node.js apps running and restart them on failure.
Practice. Write an Ansible playbook that installs Node.js, deploys your app as a systemd service and configures Monit to restart it.
Stage 9 Performance, scaling and operations
Goal. Find and fix slow pages and endpoints, scale an app sensibly and know when it is broken in production.
Front end performance Core
Users feel performance in the browser. Core Web Vitals measure it: Largest Contentful Paint for loading, Interaction to Next Paint for responsiveness and Cumulative Layout Shift for visual stability. Common fixes are rendering important content on the server, splitting JavaScript by route, optimising images with modern formats and correct sizes, setting long cache lifetimes on hashed assets, and removing heavy third-party scripts.
Measure with Lighthouse and the browser Performance panel, then confirm with real user data after release. A full stack developer can also fix the cause on the server, such as a slow API response that delays the main content.
Practice. Measure Core Web Vitals for your app, fix the largest problem and record before and after numbers.
Back end and database performance Core
Most slow endpoints are slow because of the database. Log slow queries, read their EXPLAIN ANALYZE plans, add missing indexes, remove N+1 patterns, select only needed columns and paginate large results. Use connection pooling so the database is not overwhelmed by connections.
Then look at the application: run independent calls in parallel, cache expensive results in Redis, move slow work to background jobs and compress responses. Profile before changing code, and measure percentiles such as p95 and p99 latency, not only the average, because the slowest requests are what users complain about.
Practice. Profile your slowest endpoint, reduce its p95 latency by half and write down which change mattered most.
Scaling web applications Recommended
Scale vertically (a bigger machine) until it stops being simple, then horizontally (more machines behind a load balancer). Horizontal scaling needs stateless app servers: keep sessions in Redis or cookies, and files in S3, not on local disk. Put static assets and cacheable pages behind a CDN.
For the database, add read replicas for read-heavy loads, cache hot data, and only consider sharding when one primary truly cannot cope. Queues absorb spikes so a sudden burst of orders does not overload downstream services. Rate limiting protects the system from abusive or buggy clients.
Practice. Run two instances of your API behind a load balancer and prove sessions and uploads still work.
Observability: logs, metrics and traces Core
You cannot fix what you cannot see. Write structured logs in JSON with a request ID that follows the request across services. Collect metrics such as request rate, error rate and latency per endpoint, plus queue length and database connections. Distributed tracing, often with OpenTelemetry, shows where time goes across front end, API, database and third-party calls.
Front end error monitoring captures JavaScript exceptions with source maps. Set alerts on symptoms users feel, such as error rate or latency above a threshold, not on every CPU spike. Dashboards should answer "is the app healthy right now" at a glance.
Practice. Add structured logging with request IDs, an error rate metric and one alert to a deployed app.
Incidents and reliability Recommended
Things will break in production. When they do, the first job is to reduce user impact: roll back, disable a feature flag or scale up. Then find the root cause. Communicate status clearly to the team and affected users while you work.
After the incident, write a blameless review: timeline, impact, root cause and actions such as tests, alerts or design changes that stop it happening again. Prevent incidents with safe practices: small releases, feature flags, backwards-compatible migrations, health checks, automatic rollbacks and regular, tested database backups.
Practice. Run a game day: break one dependency on your staging app on purpose and practise detecting, mitigating and writing up the incident.
Stage 10 Interview readiness and AI-assisted work
Goal. Prepare for coding, practical build and system design rounds, and use AI tools productively and safely.
Data structures and algorithms Core
Many companies include a general coding round. Full stack candidates usually face easy to medium problems: arrays and strings, hash maps, two pointers, sliding windows, stacks and queues, recursion, trees and basic graph search. Explain your approach before coding, state time and space complexity, and test edge cases out loud.
Some companies prefer practical tasks instead, such as implementing a rate limiter, an LRU cache, pagination logic or a debounced search. Prepare both. Practise in coding practice and follow a structured plan of patterns rather than random problems.
Practice. Solve two problems a day for four weeks, including an LRU cache and a token-bucket rate limiter.
Full stack system design Core
Mid and senior candidates usually get a design round: a URL shortener, a booking system, a chat app, a file-sharing service or a job board. Use a steady structure: clarify requirements and scale, define the API, design the data model, sketch the architecture (client, CDN, load balancer, app servers, database, cache, queue, object storage), then go deep on the hardest part.
Full stack interviewers value end-to-end thinking: how the UI handles loading and failure, how pagination works from SQL to the screen, how uploads go straight to S3, and how concurrency is handled in the database. Practise with system design practice.
Practice. Design a ticket booking system in 45 minutes, covering the API, schema, double-booking prevention and the checkout UI.
AI-assisted development Recommended
AI coding assistants such as GitHub Copilot, Cursor and Claude Code can scaffold endpoints, write tests, explain unfamiliar code and refactor across many files. They are most useful when you give clear context and have tests to check their work.
Generated code often looks right and is subtly wrong: missing authorisation checks, SQL built from strings, unhandled errors or outdated APIs. Review every change as if a new teammate wrote it. Interviewers increasingly ask how you use these tools; a good answer shows speed with judgement, and a clear sense of what you would never accept without checking.
Practice. Use an AI assistant to add a feature with tests, then review the diff and list every issue you had to fix.
Building AI features into products Optional
Many full stack roles now include adding AI features: summarising, search over company documents, drafting replies or extracting data from uploads. The usual pattern is your server calling a model provider's API, never the browser holding the key. Stream responses to the UI for a responsive feel, store conversations, and enforce per-user rate limits and cost controls.
Retrieval-augmented generation stores embeddings of your documents, often in PostgreSQL with pgvector, finds relevant passages for each question and includes them in the prompt. Treat model output as untrusted input: validate structured output against a schema and never render it as raw HTML.
Practice. Add a "summarise this document" feature that streams the result to the UI and limits each user to ten calls a day.
Projects to build
Build these in order. Each one should end up in a public repository with a short README that explains your decisions.
- Notes app with authenticationBeginner
Build a notes app with a React front end, a Node.js REST API and PostgreSQL. Users sign up, log in with a session cookie and create, edit and delete only their own notes. Add validation on both sides, a consistent error format and a few integration tests.
React · REST · PostgreSQL · Sessions
- Job board with search and paginationIntermediate
Build a job board where companies post roles and candidates search by keyword, location and salary range. Use PostgreSQL full-text search, cursor pagination, URL-based filters, server-rendered listing pages in Next.js and an admin role for moderation. Measure and index the slow queries.
Next.js · SQL and indexes · Authorisation · Rendering strategies
- Real-time team chatIntermediate
Build chat rooms with WebSockets, message history in PostgreSQL, presence and typing indicators through Redis, and file attachments uploaded directly to S3 with presigned URLs. Run two server instances to prove broadcasting works across them.
WebSockets · Redis pub/sub · S3 · Horizontal scaling
- Booking system with background jobsAdvanced
Build a booking app for a small business with time slots, double-booking prevention in the database, confirmation and reminder emails sent through SES by a queued worker, and an admin dashboard. Write tests for concurrent bookings and job retries.
Transactions · Queues · SES · Testing
- Multi-tenant SaaS deployed to AWSAdvanced
Build a small SaaS with organisations, roles and per-tenant data isolation. Package it with Docker, describe the VPC, RDS database, S3 bucket and Route53 records in Terraform, and deploy through GitHub Actions with staging and production. Add structured logs, an error alert and a written incident runbook.
Terraform · AWS · CI/CD · Observability
Preparation plan
- Weeks 1–2JavaScript, HTTP and algorithms fundamentals
Revise closures, promises, the event loop and array methods; implement debounce and Promise.all from memory.
Revise HTTP methods, status codes, headers, cookies and CORS; write short answers in your own words.
Solve one or two easy problems a day in coding practice.
- Weeks 3–4SQL, data modelling and API design
Design three schemas from prompts (bookings, job board, chat) and write the key queries for each.
Practise joins, aggregates, window functions and indexes in SQL practice.
Build a REST API with validation, pagination and a consistent error format in under three hours.
- Weeks 5–6React, authentication and the practical build
Build a full CRUD feature with a React UI, Node.js API, PostgreSQL and tests in under 90 minutes, three times.
Add sessions, password hashing, roles and per-user authorisation to one project and write tests for access control.
Move to medium algorithm problems: hash maps, two pointers, trees and recursion.
- Weeks 7–8Deployment, performance and security
Containerise your best project, deploy it through GitHub Actions and add logging and one alert.
Profile one slow page and one slow endpoint, fix them and record the numbers for interview stories.
Revise caching, Redis, race conditions, migrations and the main web attacks.
- Weeks 9–10System design, behavioural stories and mock interviews
Practise five system design prompts in system design practice with a 45-minute timer.
Write and rehearse six to eight behavioural stories.
Do three full mock interviews and track weak areas in progress page.
Interview questions
Try to answer each question out loud before you open the answer.
Design the REST endpoints for a blog with posts and comments.Junior
I would use GET /posts with cursor pagination and filters, POST /posts returning 201 with the new resource, GET /posts/{id}, PATCH /posts/{id} for partial updates and DELETE /posts/{id} returning 204. Comments are nested where they belong to a post: GET /posts/{id}/comments and POST /posts/{id}/comments, with DELETE /comments/{id} for direct access. I return 400 or 422 for invalid input, 401 when not signed in, 403 when not allowed, 404 for missing items, and one consistent JSON error shape. Only the author or an admin may edit or delete.
Write a query for the top three customers by total spend in the last 30 days.Junior
SELECT c.id, c.name, SUM(o.total) AS spend
FROM customers c
JOIN orders o ON o.customer_id = c.id
WHERE o.created_at >= NOW() - INTERVAL '30 days'
AND o.status = 'paid'
GROUP BY c.id, c.name
ORDER BY spend DESC
LIMIT 3;I filter before grouping, include only paid orders so refunds and drafts do not count, and group by the ID as well as the name because names are not unique. If ties matter, I would use DENSE_RANK in a CTE. An index on orders (created_at) or (customer_id, created_at) keeps it fast.
How should passwords be stored?Junior
Never in plain text and never with reversible encryption or a fast hash such as SHA-256. I use a slow, salted password hashing algorithm such as Argon2id or bcrypt through a maintained library, which adds a unique salt per password and makes brute force expensive. On login I compare with the library's verify function. I also rate limit login attempts, support multi-factor authentication, make reset tokens single-use and short-lived, and never log passwords. Where possible I would offer sign-in through OpenID Connect or passkeys so we store fewer passwords at all.
What is the difference between a Docker image and a container, and why use multi-stage builds?Junior
An image is a read-only template built from a Dockerfile: the file system and settings needed to run the app. A container is a running instance of an image with its own writable layer, process and network. You can run many containers from one image. Multi-stage builds use one stage with compilers and dev dependencies to build the app, then copy only the output into a slim final image. The result is smaller, faster to pull and has fewer packages that could contain vulnerabilities.
What is the N+1 query problem and how do you fix it?Mid
It happens when code loads a list with one query and then runs one more query per item to load related data, for example 100 posts and then 100 separate author lookups. It is common with ORMs that lazy-load relations, and it gets slower as data grows. I spot it by logging query counts per request or in an APM trace. Fixes are a join, the ORM's eager loading option, a single WHERE id IN (...) query, or a batching helper such as DataLoader in GraphQL. Then I add a test or metric so it does not come back.
Sessions or JWTs for a web app's authentication?Mid
For a browser app talking to its own back end, I default to server sessions: a random ID in an HttpOnly, Secure, SameSite cookie, with session data in Redis or the database. They are simple and can be revoked instantly. JWTs help when many services must verify identity without a shared store, or for third-party API access. The cost is revocation: a stolen token stays valid until expiry, so I keep access tokens short-lived, rotate refresh tokens and store them in HttpOnly cookies, not localStorage. Either way, authorisation checks still happen on every request.
An endpoint in Node.js becomes slow for all users when one user exports a large report. Why, and what would you do?Mid
The export probably does heavy synchronous work, such as building a huge file or JSON string in memory, on the main thread. Node.js runs JavaScript on one thread, so while that work runs, the event loop cannot serve other requests. I would confirm with a profile or an event loop delay metric. Fixes: move the export to a background job that writes to S3 and notifies the user, stream rows from the database instead of loading them all, or use worker threads for CPU work. I would also paginate or limit the export size.
Two users try to book the last seat at the same moment. How do you prevent double booking?Mid
Application code that reads availability and then writes a booking has a race, so the database must enforce the rule. Options: a conditional update such as UPDATE events SET seats_left = seats_left - 1 WHERE id = $1 AND seats_left > 0 and check the affected row count; a unique constraint on the seat and event so the second insert fails; or SELECT ... FOR UPDATE inside a transaction to lock the row. I would return 409 to the losing request with a clear message, and write a test that fires concurrent requests to prove it.
How would you add caching with Redis to a slow product page API?Mid
I would use cache-aside: look up a key such as product:42; on a hit return it; on a miss read from PostgreSQL, store the result with a TTL and return it. When a product is updated, delete the key so the next read refreshes it. To avoid a stampede on popular keys, use a short lock or request coalescing so only one request rebuilds the value, and add a little random jitter to TTLs. I would measure hit rate and latency before and after, and make sure the app still works if Redis is down.
A user says a page takes eight seconds to load. How do you find the cause across the stack?Mid
I reproduce it, then use the browser network panel to see whether time is spent waiting for the HTML or an API call, downloading large files, or running JavaScript. If an API is slow, I check its trace or logs for that request ID to see time in the database, external calls or application code. For a slow query I read the EXPLAIN ANALYZE plan and look for missing indexes or N+1 patterns. For front end causes I check bundle size, images and long tasks. I fix the largest cost first, then verify with metrics.
How would you let users upload large files such as videos?Mid
I would avoid passing the file through the API servers. The client asks the API for a presigned S3 upload URL, scoped to a key, content type and size limit, and uploads directly to S3, using multipart upload for large files so it can resume. When it finishes, the client tells the API, or an S3 event notifies a worker, which validates the file, scans it and processes it, such as transcoding, in a background job. The UI shows progress and handles failures. Files are private and served through signed URLs or a CDN.
How do you run a database migration without downtime?Senior
I use expand and contract. First, deploy an additive change that old code tolerates: add the new column as nullable or with a default, or a new table. Then deploy code that writes to both old and new places and reads from the old. Backfill existing rows in small batches. Switch reads to the new column, then stop writing the old one. Finally, in a later release, drop the old column. I avoid long locks by creating indexes concurrently in PostgreSQL and test the migration on a copy of production-sized data.
Design a URL shortener.Senior
Requirements: create short links, redirect fast, optional expiry and click counts; reads far outnumber writes. API: POST /links returns a code; GET /{code} returns a 301 or 302 redirect. Codes come from a base62-encoded ID or random string with a uniqueness check. Store links in PostgreSQL with a unique index on the code. Cache hot codes in Redis and use 302 if we need accurate click counts, since browsers cache 301s. Record clicks asynchronously through a queue to keep redirects fast. Add rate limiting and malware checks on creation to stop abuse.
Explain CORS and CSRF and how they relate in a full stack app.Junior
CORS is a browser rule: a page from one origin cannot read responses from another origin unless the server returns headers such as Access-Control-Allow-Origin. It protects users' data from other sites' scripts, not the server from clients. CSRF is an attack where another site makes a logged-in user's browser send a request to my API with their cookies. CORS does not stop that, because the request is still sent. Defences are SameSite cookies, CSRF tokens for cookie-authenticated forms, and not changing state on GET requests.
How do you decide whether to split a monolith into microservices?Senior
I start from the problem, not the pattern. Good reasons are parts with very different scaling or reliability needs, teams blocked by each other in one codebase, or a component with separate security requirements. Costs include network failures, distributed transactions, harder debugging, more deployment and monitoring work. Often a modular monolith with clear boundaries, separate database schemas per module and a queue for background work gives most of the benefit. If we do split, I would extract one well-bounded service first, behind a stable API, and measure the result.
Tell me about a feature you owned from database to UI.Mid
A strong answer names a real feature and walks through the layers: the requirement and who it served, the schema and migration, the API design and permission checks, the UI states, the tests and how it was released. Mention one hard trade-off, for example choosing server rendering for speed or adding a background job to keep a request fast, and give a measurable result such as adoption, fewer support tickets or lower latency. Close with what you would do differently.
Describe a production incident you were involved in.Mid
Choose a specific incident. Explain how it was detected, what you did first to reduce impact, such as a rollback or disabling a feature flag, and how you communicated. Then give the root cause, for example a migration that locked a large table or a cache that served another user's data, and the lasting fixes: a test, an alert, a review checklist or a design change. Show calm ownership and a blameless attitude.
How do you balance shipping quickly with code quality?Mid
I separate decisions that are hard to reverse, such as data models, public APIs and security, from those that are easy to change, such as UI layout or internal helpers. I take more care on the first group and move fast on the second. I keep quality cheap through automation: types, linting, tests and CI. When I take a shortcut on purpose, I record it as a ticket with the reason. A good example story shows a deadline met without skipping the checks that protect users' data.
Common mistakes
- Trying to learn every tool at once; build one complete stack (React, Node.js, PostgreSQL) end to end before adding more.
- Skipping HTML, CSS and JavaScript basics to jump into frameworks; weak fundamentals show up quickly in UI rounds.
- Validating input only on the front end; always validate again on the server, because anyone can call your API directly.
- Checking that a user is logged in but not that they own the record; test access to other users' data explicitly.
- Building SQL by joining strings; use parameterised queries or a query builder every time.
- Ignoring indexes and N+1 queries until production; log query counts and read query plans while you build.
- Committing secrets to Git; use environment variables, a secrets store and secret scanning in CI.
- Deploying by hand from a laptop; set up CI/CD early so every deploy is repeatable and reversible.
- Reaching for microservices or Kubernetes for a small app; start with a well-structured monolith on a simple platform.
Ready-for-interview checklist
- I can explain a full request path from browser to database and back, including DNS, HTTPS and caching.
- I can build a typed React front end with forms, routing and server-state caching.
- I can build a Node.js REST API with validation, consistent errors and pagination.
- I can design a normalised PostgreSQL schema and write joins, aggregates and window functions.
- I can prevent race conditions with transactions, constraints or conditional updates.
- I can add Redis caching and explain invalidation and stampede protection.
- I can implement secure sessions or JWTs and per-user authorisation checks.
- I can explain and prevent SQL injection, XSS, CSRF and SSRF.
- I can write unit, integration and end-to-end tests and run them in GitHub Actions.
- I can containerise an app with Docker and deploy it with CI/CD to a cloud environment.
- I can explain EC2, S3, VPC, Route53, SES and IAM, and describe infrastructure in Terraform.
- I can diagnose a slow page across front end, API and database.
- I can design a booking system or URL shortener end to end in 45 minutes.
- I can tell six behavioural stories with clear, measurable results.
Where this role leads
Back End Engineer: specialise in APIs, data, distributed systems and reliability.
Front End Engineer: specialise in UI architecture, performance and accessibility.
DevOps SRE Engineer: move deeper into infrastructure, automation and production reliability.
Software Architect: design systems across teams using your end-to-end view.
Engineering Manager or technical founder: lead a product team or build your own product.
Related roadmaps
- JavaScript RoadmapLanguage core, async, the event loop, modules and the DOM.
- TypeScript RoadmapTypes, generics, narrowing, utility types and project setup.
- React RoadmapComponents, hooks, state, data fetching, performance and testing.
- Node.js RoadmapEvent loop, modules, HTTP, streams, frameworks and deployment.
- SQL RoadmapQueries, joins, window functions, indexes and transactions.
- Docker RoadmapImages, containers, networking, volumes, Compose and security.
FAQ
How long does it take to become a full stack developer?
From zero, most people need nine to fifteen months of steady study at ten to fifteen hours a week to reach a junior full stack level with a portfolio. People who already know front end or back end development can often add the other side in three to six months. Aim for one complete stack you know well rather than many half-learned tools.
Should I learn front end or back end first?
Most people start with the front end, because HTML, CSS and JavaScript give visible results quickly and JavaScript then carries over to Node.js on the server. Add a simple back end and database as soon as you can build a basic React app, so you learn how the pieces connect early.
Which stack should I learn for full stack jobs?
A TypeScript stack of React or Next.js, Node.js and PostgreSQL appears in a large share of job posts and lets you use one language everywhere. Other common stacks pair a React front end with Python and Django, Java and Spring Boot, C# and ASP.NET Core, or Ruby on Rails. Check job listings where you want to work and pick the stack that appears most.
Do full stack developers need to know AWS and DevOps?
You need working knowledge, not specialist depth. Be able to containerise an app, set up a CI/CD pipeline, deploy to a platform or AWS, use S3 and a managed database, and read logs and metrics. Larger companies have platform teams, but full stack developers are still expected to ship and debug their own features in production.
Is full stack development still a good career with AI tools?
Yes. AI assistants speed up boilerplate, but someone still has to design data models, secure APIs, judge trade-offs and debug problems across layers. Those are exactly the skills full stack developers build. Use AI tools to work faster, and invest in fundamentals so you can tell when their output is wrong.