Skip to content

Hard Web Development Interview Questions

46 hard questions with answers. Design, trade-off and deep-dive questions asked for senior roles and at top product companies.

Topics in the hard set

MySQL Database: 8 Web Security: 8 CSS Layout and Responsive Design: 7 Hosting and Deployment: 7 DOM and Browser Events: 5 JavaScript Core: 4 PHP Programming: 4 HTML Fundamentals: 3
Solved — hardStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

Explain the critical rendering path and how HTML structure affects it.

Save to ▾
Show answer
The browser parses HTML into the DOM, CSS into the CSSOM, combines them into a render tree, then calculates layout and paints pixels. CSS in the head is render-blocking and synchronous scripts block parsing, so their placement decides how fast the first paint appears. Good practice is to inline small critical CSS, defer non-essential scripts, preload key fonts and hero images, and keep the initial HTML lean.
02

A contact form is receiving hundreds of spam submissions daily. What do you do?

Save to ▾
Show answer
I would layer defences rather than rely on one trick. On the front end, add a hidden honeypot field that bots fill and humans do not, and add an invisible CAPTCHA such as reCAPTCHA v3 or Turnstile. On the server, validate every field, apply rate limiting per IP, reject submissions that arrive too fast after page load, and log patterns. Real protection must be server side because bots skip JavaScript.
03

Lighthouse shows a poor Largest Contentful Paint caused by the hero image. What steps do you take?

Save to ▾
Show answer
First I would compress the image and serve it in AVIF or WebP at the correct size using srcset. I would remove loading='lazy' from it, add fetchpriority='high' and a preload link in the head, and make sure it is in the initial HTML rather than injected by JavaScript. I would also serve it from a CDN and check that render-blocking CSS is not delaying the paint.
04

What is a stacking context and why does z-index sometimes not work?

Save to ▾
Show answer
A stacking context is an independent layer group in which z-index values are compared. It is created by the root, positioned elements with a z-index, and properties like opacity below 1, transform, filter and isolation: isolate. A child can never appear above something outside its parent's stacking context, no matter how high its z-index is. Fixing it usually means moving the element or removing the property that created the context.
05

What are container queries and how do they differ from media queries?

Save to ▾
Show answer
Media queries respond to the viewport size, while container queries respond to the size of a parent element. You mark a parent with container-type: inline-size and then write @container (min-width: 400px) rules for its children. This lets a card component change layout depending on whether it sits in a narrow sidebar or a wide main area, making components truly reusable. They are supported in all modern browsers.
06

Compare BEM and utility-first approaches to CSS architecture.

Save to ▾
Show answer
BEM names classes as block__element--modifier, such as card__title--large, which keeps styles scoped and readable in large codebases. Utility-first frameworks like Tailwind CSS compose small single-purpose classes in the markup, which speeds up development and avoids growing stylesheets. BEM gives cleaner HTML, utilities give consistency and smaller final CSS after purging. The right choice depends on team size, design system and tooling.
07

Use clamp() to create fluid typography.

Save to ▾
Show answer
clamp(min, preferred, max) scales text smoothly between limits: h1 { font-size: clamp(1.75rem, 1rem + 3vw, 3.5rem); } p { font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem); } The heading never goes below 28 pixels on phones or above 56 pixels on large screens. Mixing rem with vw in the middle value keeps text zoomable for accessibility, unlike pure vw values.
08

The site's main CSS file is 400 KB and first paint is slow. How do you optimise it?

Save to ▾
Show answer
I would run the Coverage tab in DevTools to measure unused CSS, then remove dead rules with a tool like PurgeCSS. I would extract critical above-the-fold CSS and inline it, loading the rest asynchronously. Splitting styles per page or route, minifying, enabling Brotli compression and caching with long expiry headers also help. Finally I would replace heavy frameworks where only a few components are used.
09

A third-party widget's CSS keeps overriding your button styles. How do you handle it?

Save to ▾
Show answer
First I would check which selector wins in DevTools and why. Options include scoping my styles with a more specific component class, using CSS cascade layers so third-party CSS sits in a lower layer, or loading the widget inside an iframe or Shadow DOM so its styles are isolated. I would avoid adding !important everywhere, because it starts an override war that becomes impossible to maintain.
10

Your page has a high Cumulative Layout Shift because of fonts and ads. How do you reduce it?

Save to ▾
Show answer
For fonts I would preload the main font file, use font-display: swap or optional, and tune fallback fonts with size-adjust so the swap does not move text. For ads and embeds I would reserve space with a fixed min-height or aspect-ratio box before they load. I would also set width and height on all images and avoid inserting banners above existing content after load.
11

Explain the JavaScript event loop.

Save to ▾
Show answer
JavaScript runs on a single main thread with a call stack. Asynchronous work like timers, network requests and events is handled by browser APIs, and their callbacks are queued. After the stack is empty, the event loop first runs all microtasks, such as promise callbacks and queueMicrotask, then takes the next macrotask, such as a setTimeout callback. That is why a resolved promise logs before a setTimeout of 0.
12

Explain prototypal inheritance in JavaScript.

Save to ▾
Show answer
Every object has an internal link to another object called its prototype. When a property is not found on the object, JavaScript looks up the prototype chain until it reaches Object.prototype and then null. Class syntax is a cleaner layer over this model: class Admin extends User sets Admin.prototype to inherit from User.prototype. Methods defined on the prototype are shared across instances, which saves memory.
13

What are iterators and generators in JavaScript?

Save to ▾
Show answer
An iterator is an object with a next() method returning { value, done }, and any object with a Symbol.iterator method can be used in for...of loops and spread syntax. A generator function, written function*, creates iterators easily: each yield pauses execution and returns a value, resuming on the next call. Generators are useful for lazy sequences, such as paginated API results, without building huge arrays in memory.
14

A dashboard page becomes slower the longer it stays open. What could cause it?

Save to ▾
Show answer
This points to a memory leak. Typical causes are setInterval timers never cleared, event listeners added repeatedly on re-render, detached DOM nodes still referenced in arrays, and growing caches. I would take heap snapshots in the DevTools Memory tab a few minutes apart and compare retained objects. Fixes include clearInterval on cleanup, removeEventListener or AbortController for listeners, and limiting cached data size.
15

What is the difference between reflow and repaint?

Save to ▾
Show answer
Reflow, or layout, happens when the browser recalculates positions and sizes, triggered by changing width, adding elements, or reading offsetHeight after a write. Repaint happens when only visual styles like colour or background change. Reflow is more expensive and can cascade to the whole page. Animating transform and opacity avoids both because they are handled by the compositor, which keeps animations smooth at 60 frames per second.
16

Implement infinite scroll using IntersectionObserver.

Save to ▾
Show answer
Observe a sentinel element at the bottom of the list: const sentinel = document.querySelector('#sentinel'); let page = 1, loading = false; const observer = new IntersectionObserver(async ([entry]) => { if (!entry.isIntersecting || loading) return; loading = true; const res = await fetch('/api/posts?page=' + (++page)); const posts = await res.json(); if (!posts.length) observer.disconnect(); posts.forEach(renderPost); loading = false; }, { rootMargin: '200px' }); observer.observe(sentinel); It is far cheaper than listening to every scroll event.
17

The page stutters while scrolling because of a scroll event handler. How do you fix it?

Save to ▾
Show answer
Scroll events fire many times per second, so heavy work in the handler blocks the main thread. I would throttle the handler or batch DOM writes inside requestAnimationFrame, mark listeners as { passive: true }, and avoid reading layout properties like offsetTop after writing styles. For tasks like lazy loading, sticky effects or reveal animations, I would replace the handler with IntersectionObserver or CSS position: sticky.
18

Users click the Pay button twice and get charged twice. How do you prevent it?

Save to ▾
Show answer
On the front end, I would disable the button and show a loading state as soon as the first click is handled, and re-enable it only on error. But the real fix must be on the server: generate an idempotency key or order id per checkout, and reject or ignore a second request with the same key. Payment gateways support idempotent requests for exactly this reason.
19

Rendering a table with 5,000 rows freezes the browser. What are your options?

Save to ▾
Show answer
Creating thousands of nodes at once blocks the main thread. Options are server-side pagination, rendering in chunks with requestAnimationFrame, or virtual scrolling where only the 30 to 50 visible rows exist in the DOM at any time. I would also build rows in a DocumentFragment, avoid layout reads inside loops, and use CSS content-visibility: auto so off-screen rows skip rendering work.
20

What does declare(strict_types=1) do?

Save to ▾
Show answer
By default PHP coerces scalar types, so passing '5' to a function expecting int silently works. With declare(strict_types=1) at the top of a file, calls made from that file must pass exactly the declared types, or a TypeError is thrown. It catches bugs early, especially in APIs where values arrive as strings. It applies per file, to calls made from the file, not to the whole project.
21

Write secure PHP code to handle an image upload.

Save to ▾
Show answer
Check errors, size and real MIME type, then store with a random name: if ($_FILES['photo']['error'] === UPLOAD_ERR_OK && $_FILES['photo']['size'] < 2_000_000) { $mime = (new finfo(FILEINFO_MIME_TYPE))->file($_FILES['photo']['tmp_name']); $allowed = ['image/jpeg' => 'jpg', 'image/png' => 'png', 'image/webp' => 'webp']; if (isset($allowed[$mime])) { $name = bin2hex(random_bytes(16)) . '.' . $allowed[$mime]; move_uploaded_file($_FILES['photo']['tmp_name'], __DIR__ . '/uploads/' . $name); } } Never trust the original filename or extension.
22

A PHP page takes 8 seconds to load. How do you find the bottleneck?

Save to ▾
Show answer
I would measure before guessing, using a profiler like Xdebug or Blackfire, or simple microtime logs around sections. Usually the cause is database queries, such as an N+1 pattern running a query inside a loop, missing indexes, or slow external API calls. Fixes include joining or eager loading, adding indexes, caching results in Redis, making API calls async with a queue, and enabling OPcache.
23

You must upgrade an old project from PHP 7.4 to PHP 8.3. How do you plan it?

Save to ▾
Show answer
I would first set up a staging copy and run a static analyser like PHPStan or Rector with PHP 8 rules to list incompatible code, such as removed functions, changed string comparisons and stricter type errors. Then I would update Composer dependencies to versions supporting PHP 8.3, fix deprecations, run the test suite and manual checks, and deploy with a rollback plan. PHP 7.4 has been unsupported since 2022.
24

How do indexes work and when can they hurt performance?

Save to ▾
Show answer
InnoDB indexes are B+ trees that let MySQL find rows without scanning the whole table, which speeds up WHERE, JOIN and ORDER BY on indexed columns. A composite index follows the leftmost prefix rule. Indexes cost extra disk space and slow down INSERT, UPDATE and DELETE because each index must be updated. Low-selectivity columns like gender rarely benefit, and functions on columns in WHERE can stop index use.
25

How do you read the output of EXPLAIN in MySQL?

Save to ▾
Show answer
EXPLAIN shows how MySQL plans to run a query. Key columns are type, where ALL means a full table scan and ref or eq_ref mean index lookups; key, the index actually chosen; rows, the estimated rows examined; and Extra, where 'Using filesort' or 'Using temporary' signal costly operations. EXPLAIN ANALYZE in MySQL 8 runs the query and shows real timings, which helps confirm an optimisation.
26

Explain transaction isolation levels in MySQL.

Save to ▾
Show answer
READ UNCOMMITTED allows dirty reads of uncommitted data. READ COMMITTED sees only committed data but the same query can return different results within a transaction. REPEATABLE READ, the InnoDB default, gives a consistent snapshot for the whole transaction and uses gap locks to prevent most phantom rows. SERIALIZABLE is the strictest and slowest. Higher isolation means fewer anomalies but more locking and contention.
27

Find the top 3 highest-paid employees in each department.

Save to ▾
Show answer
Use a window function in MySQL 8: WITH ranked AS ( SELECT name, department_id, salary, DENSE_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rnk FROM employees ) SELECT name, department_id, salary FROM ranked WHERE rnk <= 3; PARTITION BY restarts ranking per department. DENSE_RANK keeps ties together, while ROW_NUMBER would return exactly three rows even if salaries tie.
28

A search query on a 2 million row products table takes 6 seconds. How do you speed it up?

Save to ▾
Show answer
I would run EXPLAIN to see if it does a full table scan. If the WHERE uses LIKE '%phone%', a normal index cannot help, so I would add a FULLTEXT index with MATCH AGAINST or use a search engine like Elasticsearch or Meilisearch. For filters such as category and price, a composite index in the right order helps. I would also select only needed columns and cache popular searches.
29

Your application logs show frequent deadlock errors. What do you do?

Save to ▾
Show answer
A deadlock happens when two transactions each hold a lock the other needs; InnoDB kills one. I would read SHOW ENGINE INNODB STATUS to see the conflicting queries. Fixes include accessing tables and rows in a consistent order, keeping transactions short, adding indexes so updates lock fewer rows, and avoiding user interaction inside a transaction. The application should also retry the failed transaction once or twice.
30

Pagination becomes very slow on later pages. Why, and how do you fix it?

Save to ▾
Show answer
LIMIT 20 OFFSET 100000 forces MySQL to read and discard 100,000 rows before returning 20, so deep pages get slower. Keyset or cursor pagination fixes this: remember the last seen id and query WHERE id < :last_id ORDER BY id DESC LIMIT 20, which uses the index directly. It suits infinite scroll and APIs. For numbered pages, limiting maximum depth or caching counts also helps.
31

Someone accidentally ran DELETE without a WHERE clause on production. How do you recover?

Save to ▾
Show answer
First I would stop writes to that table to avoid further damage and inform the team. Then I would restore the latest backup to a separate server and, if binary logging is enabled, replay binlog events up to just before the bad statement using mysqlbinlog for point-in-time recovery. Finally I would copy the recovered rows back. Afterwards I would enable safe-updates mode and restrict production access.
32

Which HTTP security headers should every website send?

Save to ▾
Show answer
Strict-Transport-Security forces HTTPS for future visits. Content-Security-Policy restricts where scripts, styles and images can load from, reducing XSS impact. X-Content-Type-Options: nosniff stops MIME sniffing. frame-ancestors in CSP or X-Frame-Options prevents clickjacking. Referrer-Policy controls what URL information leaks to other sites, and Permissions-Policy disables unused features like camera. Tools like securityheaders.com grade your configuration quickly.
33

Add security headers through Nginx configuration.

Save to ▾
Show answer
Place these in the server block: add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains' always; add_header X-Content-Type-Options 'nosniff' always; add_header Referrer-Policy 'strict-origin-when-cross-origin' always; add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:; frame-ancestors 'none'" always; add_header Permissions-Policy 'camera=(), microphone=()' always; Start CSP in Content-Security-Policy-Report-Only mode to find what breaks before enforcing it.
34

A user can view another user's invoice by changing the id in the URL. What is this and how do you fix it?

Save to ▾
Show answer
This is an Insecure Direct Object Reference, a form of broken access control, the top OWASP risk. The fix is an authorisation check on every request: fetch the invoice with WHERE id = ? AND user_id = ? using the logged-in user's id from the session, and return 404 if not found. Using random UUIDs makes guessing harder but is not a replacement for authorisation checks.
35

An attacker uploaded a PHP web shell through the profile picture feature. How did it happen and how do you prevent it?

Save to ▾
Show answer
The upload likely trusted the file extension or the browser-sent MIME type and saved files inside a web-accessible folder where PHP executes. To prevent it, verify the real type with finfo, re-encode images with GD or Imagick, rename files randomly with safe extensions, store uploads outside the web root or on object storage, and disable PHP execution in the uploads directory through server configuration.
36

Design a secure forgot-password flow.

Save to ▾
Show answer
Show the same message whether or not the email exists to avoid account enumeration. Generate a long random token with random_bytes, store only its hash with a short expiry such as 30 minutes, and email a one-time link. On reset, verify the hash and expiry, set the new password with password_hash, delete the token and invalidate existing sessions. Rate-limit the request endpoint to prevent email flooding.
37

Before launching a new web application, how would you run a basic security review?

Save to ▾
Show answer
I would walk through the OWASP Top 10: access control on every route, injection, authentication, session settings, misconfiguration and outdated components. I would run automated scanners like OWASP ZAP, check dependencies with composer audit and npm audit, verify HTTPS and security headers, and confirm error pages do not leak stack traces. Finally, I would test key flows manually as a normal user trying to access admin pages.
38

Users report being redirected to a gambling site from your pages. What do you check?

Save to ▾
Show answer
This often comes from injected JavaScript or a compromised third-party script. I would check the page source and Network tab for unfamiliar scripts, inspect .htaccess for malicious rewrite rules, search the database and theme files for obfuscated code like base64_decode or eval, and review recently changed files on the server. A strict CSP and Subresource Integrity on CDN scripts help prevent repeat incidents.
39

Describe how you would respond if your website suffered a data breach.

Save to ▾
Show answer
Situation: in a past project, unusual admin logins were detected at night. Task: as the lead developer, I had to contain and investigate. Action: I disabled the affected accounts, rotated credentials, preserved logs, found a reused weak password, and coordinated with management on informing users as required by India's DPDP Act. Result: no customer data was exfiltrated, and we enforced two-factor authentication for all admin accounts.
40

Write an Nginx server block for a PHP application using PHP-FPM.

Save to ▾
Show answer
A typical configuration: server { listen 80; server_name example.com; root /var/www/app/public; index index.php; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include fastcgi_params; fastcgi_pass unix:/run/php/php8.3-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; } location ~ /\. { deny all; } } Pointing root to public keeps .env and source files out of reach.
41

Create a GitHub Actions workflow that deploys on every push to main.

Save to ▾
Show answer
Store the SSH key as a repository secret: name: Deploy on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: composer install --no-dev && vendor/bin/phpunit - name: Deploy over SSH uses: appleboy/ssh-action@v1 with: host: ${{ secrets.HOST }} username: deploy key: ${{ secrets.SSH_KEY }} script: cd /var/www/app && ./deploy.sh Tests run first, so a failing build never deploys.
42

A results website expects ten times normal traffic on announcement day. How do you prepare?

Save to ▾
Show answer
I would load test with tools like k6 or JMeter to find the breaking point, then cache result pages aggressively using a CDN and Redis. The database should have proper indexes, and read-heavy queries could go to replicas. On cloud, I would configure auto-scaling and pre-warm extra instances before the announcement. A lightweight static fallback page and a queue for heavy tasks keep the site responsive under peak load.
43

How would you deploy updates without any downtime?

Save to ▾
Show answer
I would use atomic releases: upload the new version into a fresh release folder, install dependencies and build assets there, then switch a current symlink in one step and reload PHP-FPM. Database migrations must be backward compatible, such as adding columns before code uses them, so old and new code both work during the switch. With multiple servers, rolling or blue-green deployment behind a load balancer achieves the same.
44

A client wants to move a growing site from shared hosting to a VPS. How do you plan the migration?

Save to ▾
Show answer
I would set up the VPS with Nginx, PHP-FPM, MySQL, firewall and SSL, matching PHP versions and extensions. Then I would copy files with rsync, export and import the database, and test the site using a hosts file entry before touching DNS. After lowering the TTL, I would do a final data sync during low traffic, switch DNS, monitor logs, and keep the old hosting live for a few days as fallback.
45

How do you manage configuration and secrets across local, staging and production?

Save to ▾
Show answer
I keep code identical across environments and change only configuration through environment variables, usually loaded from a .env file that is never committed. A .env.example documents required keys without values. In production, secrets live in the server environment, the CI secret store or a cloud secrets manager. Each environment has separate database credentials and API keys, so a staging leak cannot affect production.
46

How have you helped a junior developer learn deployment?

Save to ▾
Show answer
Situation: a new joiner was nervous about deploying to production. Task: I was asked to make them independent within a month. Action: I wrote a step-by-step deployment checklist, let them deploy to staging while I watched, then paired on two production releases with them driving. Result: they handled releases alone after three weeks and later improved our checklist with a rollback section.

Frequently asked questions

Who should practise hard Web Development questions?

Candidates targeting senior roles or top product companies, and anyone who finds the medium set easy.

How should I practise these?

Answer each question aloud before opening the answer, mark it as solved only when your answer matches the key idea, and save misses to Last-Minute Revision.

Other difficulty levels