Learning Paths

Full-Stack Web

HTML, TypeScript, React, Node and databases — in the order that lets each one earn the next, ending in a product on a real domain with real users' data in it.

Finish this and you can take a product from an empty folder to a deployed, authenticated, tested application — and explain every layer of it in an interview without hand-waving.

Starts at
Beginner
Topics
6
Projects
5
Of material
212 h
  • HTML
  • CSS
  • JavaScript
  • TypeScript
  • React
  • Node.js
  • SQL
01Beginner

Web fundamentals

HTML that means something, CSS that survives a redesign, and the browser mechanics underneath both. Skipping this is why most self-taught developers plateau at the framework layer.

Foundation

  • MDN — Learn web development

    MDN Web Docs · docs · 30 h

    The reference the whole industry actually uses. Work the modules in order rather than dipping in — the sequencing is the value.

  • Responsive Web Design Certification

    freeCodeCamp · interactive · 30 h

    Typing beats reading at this stage. Build every project, including the ones that look too easy.

  • Learn CSS

    web.dev · course · 8 h

    The chapters on the box model, layout and specificity are the ones that stop CSS feeling random.

  • Learn Accessibility

    web.dev · course · 5 h

    Learn it now, while your markup is simple. Retrofitting accessibility into a finished React app is a different and much worse job.

Project

A multi-page site with no framework and no CSS library

A three-page site — hand-written HTML and CSS, no framework, no CSS library, no build step — that scores 100 on Lighthouse accessibility and is fully operable from the keyboard.

  1. Use the real elements. header, nav, main, article, footer, one h1 per page, headings that descend in order. Check each element's purpose in the MDN element reference before reaching for a div.
  2. Lay it out with modern CSS. Grid for the page, flexbox for components, custom properties for the palette and spacing scale, clamp() for type. No float layouts and no breakpoint per device.
  3. Make the navigation work without JavaScript. If it needs a menu toggle, that toggle is a real <button> with aria-expanded, reachable by Tab, closed by Escape.
  4. Prove the contrast. Every text-on-background pair through the WebAIM contrast checker at AA or better, plus a focus ring you designed deliberately rather than suppressed.
  5. Do a keyboard-only pass. Unplug the mouse and complete every task on the site. Add a skip link, and fix every place where focus order jumps or focus disappears entirely.
  6. Measure, then explain. Lighthouse on mobile: accessibility 100, performance above 95. Then list what the audit caught that you had not noticed — that list is the actual learning.

Scope guard: no framework, no Tailwind, no npm at all. Everything a framework will later do for you, do once by hand here.

02Beginner

JavaScript, properly

Closures, the event loop, promises and modules. The four things that separate someone who can copy a React tutorial from someone who can debug one.

Foundation

  • The Modern JavaScript Tutorial

    javascript.info · docs · 25 h

    The best free JavaScript text there is. Part 1 in full; Part 2 when you start touching the DOM.

Practitioner

  • Eloquent JavaScript

    Marijn Haverbeke · book · 15 h

    Harder than it looks and worth it. The exercises are where the learning is — do not read past one you have not solved.

  • The event loop

    MDN Web Docs · docs · 45 min

    Read this the first time an async bug confuses you, then again a month later. It lands differently once you have been burned.

Project

An interactive app in vanilla JavaScript

One interactive app — a task list, a quiz, a small game — with state you manage yourself, persistence to localStorage, and no libraries at all.

  1. State is one object. A single source of truth plus a render(state) that redraws from it. Never read the DOM to find out what the app currently thinks.
  2. Route every change through one function. update(action) mutates state and calls render. The moment you set textContent anywhere else, you have two sources of truth.
  3. Delegate events. One listener on the container using event.target.closest(), not one per item. Add an item afterwards and confirm it works with nothing rebound.
  4. Persist and rehydrate. Save on change, load on start, both wrapped in try/catch because private mode throws. Handle stored data written by an older version of your own shape.
  5. Cover empty, error and first-run. Nothing saved yet, a failed save, invalid input. Each gets real copy on screen, not a console message.
  6. Record where it hurt. The exact moment your own state handling became painful — a full redraw for one changed row, a listener firing twice. That paragraph is why frameworks exist.

Scope guard: zero dependencies, one HTML file and one JS module, no bundler. Reach for a framework only after you can name the problem it solves for you.

03Intermediate

TypeScript deep dive

Types as documentation that cannot go stale. Start where the compiler helps most — function boundaries and API responses.

Foundation

  • TypeScript Playground

    Microsoft · interactive · 1 h

    Keep it open beside the handbook. Every type you do not understand, paste it here and hover.

Practitioner

  • The TypeScript Handbook

    Microsoft · docs · 10 h

    The official text. Narrowing and generics are the two chapters worth re-reading.

Builder

  • Type Challenges

    GitHub · repo · 10 h

    Optional, and genuinely hard. Do the easy set only — beyond that it is a puzzle hobby, not job preparation.

04Intermediate

React and state

Components, the rules of hooks, and the harder question underneath: where each piece of state should actually live.

Practitioner

  • React — Learn

    Meta · docs · 15 h

    The rewritten docs are a genuine course. "Thinking in React" and "Managing State" are the sections that matter most.

  • Next.js — Learn

    Vercel · course · 10 h

    The interactive course builds a real dashboard with auth and a database. Do it after plain React, not instead of it.

  • TanStack Query — Overview

    TanStack · docs · 3 h

    Server state is not client state. Learning that distinction here saves you from three custom caching layers later.

Builder

Project

A React front end against a real, unreliable API

A React client for the Open-Meteo forecast API — a real service you do not control, free and keyless — that behaves correctly on a slow, failing connection rather than only on the happy path.

  1. Model four states explicitly. idle, loading, error and empty are distinct renders. A boolean isLoading cannot express "loaded, but zero results" or "loaded, then the refetch failed".
  2. Fetch properly. AbortController on unmount and on superseded requests, a timeout, retry with backoff for 5xx and never for 4xx. Fire two searches in quick succession and prove the older response cannot win.
  3. Handle real input. Debounce the location search at 300ms, keep the last good result on screen while the next loads, and keep the query in the URL so a refresh restores the view.
  4. Force every failure. DevTools on Slow 3G and Offline, a rewritten path for a 404, and a malformed response. Screenshot each state as you produce it.
  5. Stay accessible while content changes. Announce loading and errors through aria-live, keep focus stable when content swaps, and leave a keyboard-reachable retry after a failure.
  6. Cache on purpose. TanStack Query with stale times you can justify, or your own cache — either way, write down the staleness rule and why it suits weather data specifically.

Scope guard: one API, one screen, four states. Most portfolio React apps only ever render the happy path; screenshots of the other three are the differentiator.

05Intermediate

APIs and databases

The server half: HTTP as it actually works, a real relational schema, and auth you have not invented yourself.

Foundation

  • PostgreSQL — Tutorial

    PostgreSQL · docs · 4 h

    Start with the real database rather than SQLite. The difference in constraints and types shapes how you design schemas.

Practitioner

  • Node.js — Learn

    OpenJS Foundation · docs · 7 h

    Official, current, and short. The modules and async sections are the ones you will keep returning to.

  • HTTP — MDN

    MDN Web Docs · docs · 6 h

    Status codes, caching headers and CORS. Every one of these will cost you an afternoon if you learn it by trial and error instead.

  • OWASP Top 10

    OWASP · docs · 3 h

    Read before you write a login form, not after. Injection and broken access control are still where real applications get breached.

Builder

  • Use The Index, Luke

    Markus Winand · book · 5 h

    Why your query is slow, explained properly. Read it the first time a page takes two seconds to load.

Project

A REST API with sessions, roles and migrations

A REST API with registration, sessions, role-based authorisation and versioned migrations — schema designed on paper first, and tests that prove an ordinary user cannot reach another user's records.

  1. Draw the schema before any code. Tables, keys and the cardinality of every relationship. Decide now what is nullable and what is unique; both are painful to change later.
  2. Migrations from the first commit. Every schema change is a numbered up/down migration in the repository. Prove it by dropping the database and rebuilding from migrations plus a seed script.
  3. Authenticate by the book. Argon2id or bcrypt at a sensible cost, httpOnly SameSite session cookies or short-lived JWTs with refresh, rate limiting on login, and identical timing and wording for "wrong password" and "no such user" — see the OWASP authentication cheat sheet.
  4. Authorise per object, not per route. A user reads their own records and not somebody else's. Write the test that tries it — broken object-level authorisation is the most common real API vulnerability there is.
  5. Answer the concurrency question. Two clients editing one record: last write wins, optimistic locking on a version column, or a 409. Implement one and document why that one.
  6. Document and validate at the boundary. An OpenAPI spec generated from the code, request validation on entry, a consistent error shape, and pagination on every list endpoint.

Scope guard: one resource with full CRUD, two roles, no GraphQL, no microservices. The authorisation tests matter more than the endpoint count.

06Intermediate

Testing, CI and deploying to the cloud

The half of the job that turns a project into a product: tests worth having, a pipeline that runs them, and a deploy you can repeat.

Practitioner

  • Testing Library — Guiding Principles

    Testing Library · docs · 3 h

    Test what the user does, not what the component holds. That single idea makes a test suite survive a refactor.

  • Playwright — Getting started

    Microsoft · docs · 4 h

    Three end-to-end tests over the critical path are worth more than a hundred shallow unit tests. Write those three.

  • GitHub Actions documentation

    GitHub · docs · 4 h

    Get to a pipeline that lints, tests and deploys on merge. Everything after that is refinement.

  • Docker — Get started

    Docker · docs · 4 h

    "Works on my machine" is a solved problem. Learn it here and it carries straight into the Cloud & DevOps path.

Builder

  • Learn Performance

    web.dev · course · 5 h

    Core Web Vitals, and what actually moves them. Measure before you optimise anything.

Project

Ship it: your app, your domain, your pipeline

The API and front end you already built, live on your own domain, behind a pipeline that blocks a bad merge, with error tracking that tells you about a failure before a user does.

  1. One command from clone to running. Docker Compose or a documented script that gets a stranger the whole stack locally. Test it on a machine that has never seen the project.
  2. A pipeline that can say no. On every pull request: lint, type check, unit tests, and one Playwright end-to-end run through the real login flow. Branch protection on, so a red build cannot merge.
  3. Deploy on merge. Main deploys automatically, migrations run as a separate gated step, and there is a rollback procedure you have actually executed once.
  4. Configure like production. Secrets from the environment, never the repository. HTTPS with HSTS, security headers, CORS restricted to your own origin, then confirm the result with Mozilla Observatory.
  5. See failures without being told. Error tracking with source maps and release tagging, one uptime check, and structured logs carrying a request ID that ties a user's report to a log line.
  6. Five real users. Hand the URL to five people who do not know how it works, watch without helping, and write down everything they broke or could not find. Fix the top three; record what you chose not to fix.

Scope guard: one domain, one environment plus preview deploys. The list of what five strangers broke is the most valuable artefact on this path — do not skip it because the deploy already works.

Not sure this is your direction?

A three-minute counselling sample is free.

Try counselling