Prepare for Web Development interview questions grouped by experience level.
Web Development Interview Question & Answers
0-2 Years
The browser resolves the domain to an IP address through DNS, opens a TCP connection to the server (adding a TLS handshake for HTTPS), sends an HTTP request, and receives a response. The browser then parses the HTML, fetches linked resources like CSS and JS, and renders the page.
The frontend is the part of an application that runs in the user's browser and handles layout, styling, and interaction. The backend runs on a server, handling business logic, data storage, and responding to requests from the frontend or other clients.
HTTP is the application-level protocol browsers and servers use to exchange requests and responses. It defines methods like GET and POST, status codes, and headers, and it gives every web interaction a common, predictable structure.
HTTPS is HTTP layered over TLS, which encrypts traffic between the browser and server. Without it, data like passwords or cookies can be read or altered by anyone on the network path.
It's an architecture where a client, usually a browser or app, sends requests to a server, which processes them and returns a response. The client handles presentation while the server owns the shared data and logic.
DNS translates human-readable domain names into IP addresses that computers use to route traffic. Without it, people would have to remember numeric addresses for every site they visit.
GET requests fetch data and are meant to have no side effects, with parameters usually in the URL. POST requests submit data to be processed or stored, with the payload in the request body rather than the URL.
A status code tells the client how a request was handled. 200 means success, 404 means the requested resource was not found, and 500 means the server hit an unexpected error while processing the request.
The DOM is the browser's in-memory tree representation of an HTML document. JavaScript reads and modifies this tree to change what's displayed without reloading the page.
A web server is software that listens for HTTP requests and returns responses, often serving static files or forwarding requests to an application for dynamic processing. Examples include Nginx, Apache, and Node's built-in HTTP server.
A static website serves the same fixed files to every visitor, while a dynamic website generates content on the fly based on user input, database state, or session data. Most modern sites are dynamic to some degree.
An API is a defined set of endpoints a server exposes so other programs, like a frontend app or a third-party service, can request data or trigger actions. It abstracts the backend's internals behind a stable contract.
JSON is a lightweight, text-based data format that maps closely to objects and arrays in most programming languages. It's easy for both humans to read and machines to parse, which made it the default format for API payloads.
A cookie is a small piece of data a server asks the browser to store and send back on future requests to the same domain. It's commonly used to maintain login sessions or remember user preferences.
An absolute URL includes the full address, like the protocol and domain, so it works from any context. A relative URL is resolved against the current page's location, so it only makes sense within that site.
It's an approach to building pages so they adapt their layout to different screen sizes using flexible grids, relative units, and media queries. The goal is one codebase that works reasonably well on phones, tablets, and desktops.
Version control tracks changes to code over time, letting multiple people work on the same project without overwriting each other's work. Git is the standard tool, and it also lets teams roll back to earlier states when something breaks.
A framework is a set of libraries and conventions that handle common tasks like routing, templating, or database access, so developers don't rebuild the same scaffolding for every project. Examples include Express for Node.js and Django for Python.
It describes someone comfortable working across both the frontend, building what users see and interact with, and the backend, handling servers, data, and business logic. In practice it usually means broad familiarity rather than equal depth everywhere.
A database is organized storage for data that an application needs to persist beyond a single request, like user accounts or orders. Web apps typically talk to a database through queries issued from backend code.
CORS is a browser security mechanism that restricts whether a web page can make requests to a domain other than the one that served it, unless the target server explicitly allows it via response headers. It exists to prevent malicious sites from silently reading data from other origins.
A domain is the registered name, like example.com, while a hostname can include a subdomain in front of it, like api.example.com. Every hostname belongs to a domain, but a domain can have many hostnames.
Caching stores a copy of data or a response so future requests can be served faster without redoing the original work. On the web this happens at multiple layers, including the browser, a CDN, and the server itself.
A content delivery network is a distributed set of servers that cache and serve static assets from locations close to the user. It reduces latency and cuts load on the origin server.
Authentication verifies who a user is, typically through login credentials. Authorization determines what that authenticated user is allowed to do or access.
It's the part of the browser that parses HTML and CSS and turns them into the pixels shown on screen. Chrome uses Blink, Firefox uses Gecko, and Safari uses WebKit.
Localhost refers to the local machine itself, typically resolving to the loopback IP address 127.0.0.1. Developers run servers on localhost during development to test without deploying anywhere.
A port identifies a specific process listening for traffic on a machine, since one machine can run many network services at once. Web servers conventionally use port 80 for HTTP and 443 for HTTPS.
Client-side rendering sends a mostly empty page and lets JavaScript in the browser build the content after load. Server-side rendering generates the full HTML on the server before sending it, so the page has content on first paint.
An environment variable holds configuration, like an API key or database URL, outside the codebase itself. This keeps secrets and environment-specific settings out of source control and makes the same code portable across environments.
An idempotent method produces the same result no matter how many times it's called with the same input. GET, PUT, and DELETE are meant to be idempotent, while POST generally is not.
It's a key-value pair appended to a URL after a question mark, used to pass extra information with a request, like a search term or a page number. Multiple parameters are separated by ampersands.
A favicon is the small icon shown in a browser tab or bookmark list for a site. It's mostly cosmetic but also helps users visually identify a tab among many open ones.
A hosting provider runs the servers that make a website reachable on the internet, handling things like storage, uptime, and network connectivity. Examples range from simple shared hosting to cloud platforms like AWS or Vercel.
A library is a collection of functions your code calls when it needs them, leaving you in control of the overall flow. A framework calls your code at points it defines, so it dictates more of the application's structure.
Minification strips unnecessary characters, like whitespace and comments, from CSS or JavaScript files to reduce their size before shipping to production. Smaller files mean faster downloads for users.
3-6 Years
I'd start with browser dev tools to check the network waterfall and see whether the bottleneck is a slow backend response, large assets, or render-blocking scripts. From there I'd look at compression, caching headers, and whether critical resources are being loaded before they're needed.
I'd map CRUD operations to HTTP methods under a consistent path like /posts, using GET for listing and fetching, POST for creation, PUT or PATCH for updates, and DELETE for removal. I'd also plan pagination, filtering, and clear error responses from the start rather than bolting them on later.
For most apps I'd use token-based authentication, often JWTs or session cookies with proper HttpOnly and Secure flags, issued after a login flow that verifies credentials server-side. I'd also plan for token expiry, refresh flows, and making sure sensitive routes check authorization on every request rather than trusting the client.
I'd keep them as separate concerns, either in separate repos or clearly separated folders, communicating only through a defined API contract. That way the frontend and backend can be developed, tested, and even deployed independently.
On the backend I'd standardize error responses with consistent status codes and a predictable JSON shape, and log enough context to debug later. On the frontend I'd catch failed requests and show the user something actionable instead of a blank screen or a raw stack trace.
I'd start with a mobile-first layout using flexible units and media queries, then test touch targets, viewport meta settings, and load performance on a throttled connection. I'd also check that interactive elements don't rely on hover states that don't exist on touch screens.
If SEO and fast first paint matter, like for a marketing site or blog, I'd lean toward server-side rendering. If the app is highly interactive and behind a login, like a dashboard, client-side rendering with a good loading state is often simpler to build and maintain.
I'd sanitize and validate all user input, use parameterized queries to avoid injection, set proper CORS and CSP headers, and escape output to prevent cross-site scripting. I'd also make sure sensitive actions require CSRF protection and that authentication tokens aren't exposed in places like URLs or logs.
I'd keep configuration in environment variables rather than hardcoded values, with separate .env files or secret managers per environment. The codebase itself stays identical across environments, only the config it reads changes.
I'd look at what data changes rarely and cache that first, using HTTP cache headers for static assets and something like Redis for frequently read database results. I'd also make sure there's a clear invalidation strategy so stale data doesn't linger after an update.
I'd rely on a mix of unit tests for individual functions, integration tests for API endpoints, and a smaller set of end-to-end tests covering critical user flows like login or checkout. I'd also do a manual pass in the browser for anything visual that automated tests won't catch well.
I'd design the API around resources and use cases rather than what one specific client needs, keeping it generic enough that both clients consume the same endpoints. If the clients genuinely need different data shapes, I'd consider a thin API gateway or GraphQL layer to tailor responses without duplicating backend logic.
I'd set up a CI pipeline that runs tests and builds the app automatically on push, then deploys to staging first for verification before promoting to production. I'd also make sure rollbacks are simple, since deployment problems need a fast way back to a known-good state.
I'd check the browser console for the exact error, since it usually names the missing header or mismatched origin. Then I'd verify the server's CORS configuration allows the requesting origin, method, and headers, rather than guessing and adding a wildcard.
I'd validate on the frontend for immediate user feedback, but treat that as a convenience, never a security boundary. The backend always re-validates and rejects bad input, since a request can bypass the frontend entirely.
I'd start with the cheap, high-impact fixes: proper semantic HTML, alt text on images, and keyboard navigation for interactive elements. Then I'd run an automated audit tool to catch contrast and ARIA issues and prioritize fixes by how often those components appear across the app.
I'd version the API explicitly, often through the URL path like /v1/, so existing clients keep working when I introduce breaking changes in a new version. I'd also document a deprecation timeline instead of silently retiring an old version.
I'd reach for WebSockets or server-sent events instead of polling, since they avoid the overhead of repeated HTTP requests for data that hasn't changed. I'd still keep a fallback polling mechanism for environments where persistent connections are blocked.
Local storage is fine for small, non-sensitive, client-specific data like UI preferences that don't need to sync across devices. Anything that needs to persist reliably, be shared across sessions or devices, or hold sensitive data belongs in a real backend database.
I'd serve appropriately sized images for different viewports, use modern formats like WebP where supported, and lazy-load anything below the fold. I'd also check that a CDN is handling delivery rather than the origin server.
I'd use server-side sessions or a database-backed record tied to the user, rather than relying on the client to carry state between full page loads. Cookies or a token identify the session on each request so the server can look up the right state.
I'd apply limits per API key or IP address at the gateway or middleware layer, returning a 429 status with a clear retry-after header when a client exceeds it. I'd tune the limits based on realistic usage patterns rather than picking an arbitrary number.
I'd add timeouts so a slow dependency doesn't hang the whole request, and wrap calls with retries and a circuit breaker for repeated failures. On the frontend I'd design the UI to degrade gracefully rather than blocking on that one dependency.
I'd log structured events, not free-form text, including request IDs so a single user's journey can be traced across services. I'd also separate log levels clearly so alerts fire on real errors rather than routine informational noise.
6-8 Years
I'd separate the system into stateless application servers behind a load balancer, so any instance can handle any request, and push session state into a shared store like Redis. I'd also plan for horizontal scaling of both the app tier and the database early, since retrofitting statelessness later is far more disruptive than designing for it up front.
I'd look at whether specific parts of the system have genuinely different scaling, deployment, or team ownership needs, since that's where the split pays off. If the main pain is just codebase size, I'd consider a modular monolith first, because microservices add real operational overhead that isn't justified by organizational convenience alone.
I'd check dashboards for error rate and latency trends first to see if it correlates with a deploy, traffic spike, or a downstream dependency. Then I'd pull recent logs and traces for a sample of failing requests to narrow down whether it's a database connection pool exhausting, a memory issue, or a bad code path under specific input.
I'd add read replicas and route read-only queries to them, keeping writes on the primary, and layer in caching for the hottest queries. If reads still dominate after that, I'd look at denormalizing specific views or introducing a search index for the queries that don't fit a relational access pattern well.
I'd avoid routing large files through the application server entirely, instead having the client upload directly to object storage using a pre-signed URL. The application server then only handles metadata and validation, which keeps it from becoming a bottleneck or memory hog.
I'd decide per feature rather than system-wide, since something like inventory counts often needs strong consistency while something like a like counter can tolerate eventual consistency. Forcing every part of the system onto the same consistency model usually means over-engineering the parts that didn't need it.
I'd start with the authentication and authorization flows, since that's where most serious breaches originate, checking for things like broken access control on API endpoints. From there I'd review input handling for injection risks, check secrets management, and verify that dependencies are patched against known vulnerabilities.
I'd run multiple instances behind a load balancer and use a rolling deployment strategy, draining connections from old instances before terminating them. Database migrations need particular care here, since they have to stay backward compatible with the previous version of the code during the rollout window.
I'd invest early in a clear contract, using something like OpenAPI to document it, and set up contract testing so backend changes can't silently break consumers. I'd also establish a deprecation policy up front, since internal APIs tend to accumulate long-lived dependents just as fast as public ones.
I'd push for the API contract to be agreed on and mocked before either side writes production code, so the frontend can build against a stub while the backend implements the real thing. Tools that generate mock servers from an API spec make this much less painful than waiting for a working backend.
I'd use short-lived access tokens paired with a longer-lived refresh token stored in an HttpOnly, Secure cookie, so the access token can't be stolen through XSS as easily. I'd also add server-side revocation so a compromised session can be killed immediately rather than waiting for natural expiry.
I'd set explicit thresholds for metrics like time to first byte and largest contentful paint, and wire those into CI so a regression fails the build rather than getting caught after users complain. I'd also revisit the budget periodically, since what's acceptable shifts as the app and its audience change.
8-10 Years
I'd weigh the team's existing expertise heavily, since a technically superior stack the team doesn't know well often loses to a familiar one on delivery speed and reliability. I'd also factor in hiring market depth, operational maturity of the tooling, and how the choice affects long-term maintenance cost, beyond just how it looks on day one.
I'd focus standards on things that cause real cross-team pain when inconsistent, like API design conventions, logging formats, and security baselines, rather than trying to mandate every implementation detail. I'd build them collaboratively with senior engineers from each team so the standards reflect real constraints and get actual buy-in instead of being ignored.
I'd treat debt as a conscious decision made with the team, documented so it doesn't get forgotten, rather than something that just accumulates silently. The real question is whether the debt is in a part of the system that will need to scale or change often, since that's where it compounds fastest and deserves earlier repayment.
I'd weigh how core the capability is to the product's differentiation against the ongoing cost of maintaining it ourselves. Something like authentication or payments usually isn't worth building from scratch, while something central to the product's actual value proposition usually is.
I'd set a measurable baseline, like WCAG AA compliance, bake automated checks into CI so regressions get caught before release, and require manual review for new complex components. I'd also make accessibility part of the design review process itself, since retrofitting it after launch is far more expensive than building it in from the start.
I'd push for an incremental strangler-pattern approach over a big-bang rewrite, migrating one section or route at a time behind a routing layer, since a full rewrite carries high risk and often stalls under changing business priorities. I'd also define clear success metrics up front so the migration has a real finish line rather than dragging indefinitely.
I'd treat backward compatibility as close to a hard requirement, since external partners can't be coordinated the way internal teams can, and version deliberately rather than making breaking changes in place. Clear documentation and a stable changelog matter as much as the technical contract, since partners plan their own roadmaps around what we commit to.
I'd set organization-wide performance budgets tied to business-relevant metrics, like conversion rate correlation with load time, rather than arbitrary technical targets. I'd also build shared tooling that surfaces regressions automatically so teams don't have to independently reinvent performance monitoring.
I'd make the tradeoff visible with data, like incident rates or on-call load trending against feature velocity, so it becomes a shared decision with business stakeholders instead of an engineering-only frustration. Reserving explicit capacity for stability work, rather than treating it as leftover time, is usually what keeps it from being perpetually deprioritized.
I'd anchor it to where the business expects to be in a few years, like anticipated scale or new markets, rather than chasing the newest technology trend. I'd also keep the vision concrete enough to guide near-term decisions, since a vision that only matters five years out doesn't actually influence what gets built this quarter.
I'd push for the disagreement to be resolved with data and a documented set of tradeoffs rather than seniority or personal preference, often through a written design doc that lays out the options explicitly. If it's genuinely a coin flip technically, I'd default to whichever option is more reversible, since that reduces the cost of being wrong.
I'd start by identifying where cost and traffic actually correlate, since it's common for a small number of endpoints or queries to drive most of the spend. From there I'd look at caching, right-sizing compute, and whether some workloads are better suited to cheaper, less elastic infrastructure than the default autoscaling setup.
I'd look at how much duplicated effort exists across product teams solving the same infrastructure problems independently, since that's the clearest signal it's worth centralizing. The platform team's mandate needs to be narrow and genuinely useful though, or it becomes a bottleneck that slows product teams down instead of accelerating them.
I'd mandate a central secrets manager rather than environment files scattered across repos, with access scoped per service and rotated on a schedule. I'd also require that any credential leak be treated as an incident with a blameless review, so the process improves instead of just assigning fault.
10+ Years
I'd pair them on real production work that touches both ends of the stack rather than assigning isolated exercises, since the judgment calls around API contracts and data flow only show up in real systems. I'd also make a habit of reviewing their design thinking out loud, asking why they chose an approach, so they build the reasoning skill rather than just memorizing patterns.
I'd invest early in shared tooling and templates, like a standard service scaffold and CI pipeline, so new teams don't each reinvent infrastructure decisions from scratch. I'd also build a lightweight architecture review process for big decisions, enough to catch organization-wide risks without slowing every team down with unnecessary process.
I'd translate the technical risk into business terms, like potential downtime cost or customer impact, and give a small number of clear options with tradeoffs rather than a wall of technical detail. I'd also be direct about the cost of inaction, since executives need to weigh it against other priorities competing for the same budget.
I'd start by defining what reliability actually means for the business, like acceptable downtime per service tier, since not every system needs the same bar. Then I'd build the organizational muscle around it gradually, incident reviews, on-call rotations, and error budgets, so reliability becomes a shared discipline rather than one team's burden.
I'd push hard against tribal knowledge concentrated in one or two people, requiring documentation and pairing as a normal part of how critical systems get built, not an afterthought. I'd also rotate ownership periodically so more than one person genuinely understands the riskiest parts of the system, beyond just nominally having access to them.
I'd build the case with concrete costs, like maintenance burden or hiring friction, and pair it with a realistic migration path and timeline before announcing anything broadly. I'd also make sure the teams most affected are involved in shaping that migration plan, since a deprecation decided top-down without their input tends to stall in practice.
I'd focus on making good practices the path of least resistance, through templates, linting, and reusable libraries, rather than relying on everyone reading a standards document. Influence at this level comes more from what you make easy than from what you mandate.
I'd insist postmortems stay blameless and focus on systemic causes, like missing monitoring or unclear ownership, rather than individual mistakes, since a punitive culture just teaches people to hide problems. I'd also track whether the action items from past postmortems actually get completed, since an unenforced postmortem process quietly becomes theater.
I'd stay hands-on with a meaningful slice of real code, since credibility with the team and an accurate sense of the platform's actual state both come from that. The influence work, like reviewing designs across teams or shaping standards, has to be sized so it doesn't crowd out that hands-on time entirely.
I'd define clear, observable behaviors at each level, like the scope of systems someone can own or the ambiguity they can navigate independently, rather than vague labels like 'senior mindset'. I'd also make sure the framework rewards technical depth as a valid path, beyond just people who move into management.
I'd break the investment into milestones that deliver value incrementally, so the organization sees returns along the way rather than betting everything on a distant finish line. I'd also revisit the business case periodically, since a multi-year initiative needs to stay justified as priorities and market conditions shift underneath it.
I'd bring data showing the real cost of the current tradeoff, like incident frequency or engineer attrition tied to on-call burden, since abstract arguments about technical debt rarely move a room focused on quarterly goals. I'd also propose a concrete, time-boxed compromise rather than an open-ended ask, since that's usually easier for leadership to commit to.
I'd get engineers involved early in product discovery rather than handing them fully-formed specs, since that's where technical constraints and creative tradeoffs get worked out together instead of causing friction later. Consistently following through on commitments made in that collaboration is what actually builds the trust over time, not any single process.
I'd want the systems and standards I helped build to keep functioning well without me, which means prioritizing documentation, mentorship, and distributed ownership over being the single point of expertise. The clearest sign of doing this well is that the platform's quality doesn't visibly dip after you're gone.




