Hire JavaScript developers
JavaScript is the only language browsers run, so almost everyone claims it and the depth behind the claim varies more than for any other skill.
What JavaScript actually is
JavaScript is the language of the web browser and, through Node.js, a substantial server-side language as well. It is standardised as ECMAScript with a yearly release cycle, and it is the only language browsers execute natively, which guarantees its position regardless of how anyone feels about it.
It has a reputation shaped by its early years that no longer describes it well. Modern JavaScript has proper modules, classes, destructuring, async and await, and a large standard library. Most of the features people complain about are still there for backward compatibility and are avoidable in code written today. The language a competent developer writes now bears little resemblance to the language of the mid-2000s.
The hiring problem is that almost every web developer claims JavaScript, and the range is enormous. Some have deep understanding of the runtime, asynchrony and the type system's quirks. Others know a framework's API and have never needed to understand what sits beneath it. Frameworks are good enough that the second group can be productive for years, and the gap only becomes visible when something unusual happens.
The part that separates seniors from mid-levels
The event loop is the concept that underpins everything. JavaScript runs on a single thread with a queue of work; anything synchronous blocks the whole thing, including rendering in a browser. Understanding the ordering of microtasks against macrotasks is what lets someone reason about why a promise resolves before a timeout set to zero. This is not trivia: it is why an interface freezes, and why an apparently correct sequence of operations happens in the wrong order.
Closures and scope are the second area, and the one that separates people who understand the language from people who use it. A closure captures variables rather than values, which is why a loop creating callbacks can produce results everyone finds surprising the first time. Closures are also the mechanism behind most module patterns, most memory leaks in long-running applications, and a large share of the confusing behaviour in React hooks.
Equality, coercion and the handling of absent values are the third. The language has two kinds of absence and a set of coercion rules that produce results nobody would design deliberately. Competent developers avoid the problem by using strict equality and being deliberate about null against undefined, rather than by memorising the coercion table. How someone talks about this is a reasonable proxy for whether they write defensively.
Where JavaScript is used
The label “JavaScript developer” covers several jobs that share a technology and little else. These are the settings the work usually turns up in, and the one you are hiring into should shape the whole process, because the judgement each demands is different.
Browser applications
Everything running in a browser, whether through a framework or not.
Server-side services
Node.js back ends, where the same language spans both halves of a product.
Build and developer tooling
Bundlers, linters, test runners and code generators, which are themselves written in it.
Legacy browser code
Large bodies of older JavaScript, frequently jQuery-based, still running business-critical interfaces.
Cross-platform applications
Desktop and mobile applications built on web technology.
Embedded scripting
Automation inside other products, from analytics tags to spreadsheet and design tool extensions.
If a candidate's experience sits in a different row of that list from the work you have, that is not a reason to reject them, but it is the thing to probe. Ask what would be different about their approach in your setting. Someone who can answer that has transferable judgement. Someone who says it would be much the same has probably not thought about it.
Support status of the tools in this stack
JavaScript itself is standardised annually and browsers implement features continuously, so what constrains a codebase in practice is its build tooling and its runtime rather than the language specification.
JavaScript itself is not versioned as a single product, so the useful equivalent is the support status of the tools a JavaScript developer works with daily. The table is read from public release data rather than written by hand, so it states what is supported now. It is worth having in front of you during an interview: asking which of these a candidate has upgraded, and what broke, gets you further than asking how many years they have used each.
| Tool | Latest release | Release date | Maintained lines | Furthest end-of-life date |
|---|---|---|---|---|
| Node.js | 26.10.0 | 2026-09-22 | 6 | 2029-04-30 |
| React | 19.3.0 | 2026-09-09 | none published | none published |
| Angular | 22.2.0 | 2026-09-23 | 12 | 2028-06-30 |
| Vue | 3.5.43 | 2026-09-17 | 2 | 2023-12-31 |
| Next.js | 16.3.6 | 2026-09-22 | 1 | 2026-10-21 |
| Electron | 44.4.5 | 2026-09-23 | 3 | 2027-03-02 |
Source: endoflife.date public release data, read 2026-09-25. A tool with no published end-of-life dates sets its support boundary by ecosystem practice rather than by policy.
The practical use of this is in judging an estate rather than a person. A team running several of these past their support dates is usually not behind by accident; it is behind because upgrades were never anyone's job. That is worth knowing before you hire, because it tells you whether the first six months will be building new things or paying down what was deferred.
The toolchain around it
Nobody hires for JavaScript alone. The surrounding tools are where most of the day-to-day work happens, and a gap in any of them costs more time than a gap in the core library. This is the set that turns up most often on real job specifications alongside it.
- TypeScript
- Effectively the default for new commercial work, to the point that plain JavaScript is now the exception.
- A framework
- React, Vue, Angular or Svelte. Almost all commercial browser work sits inside one.
- Vite or esbuild
- Build tooling, dramatically faster than the previous generation.
- ESLint and Prettier
- Linting and formatting, standard in any professional codebase.
- Vitest or Jest
- Testing, with Testing Library for anything rendering components.
- npm or pnpm
- Dependency management, with lockfiles that must be committed.
- Playwright
- Browser automation for end-to-end testing.
- Browser developer tools
- The profiler and debugger. Developers who only use console logging are working slowly.
Related skills that frequently appear on the same specification: Node.js, React, TypeScript, Angular, Vue.js.
What to test in an interview
These are the topics that separate candidates in practice. Each one is given with why it discriminates, what a strong answer sounds like, and the response that should make you slow down. None of them requires a whiteboard.
The event loop and async ordering
The foundation of the runtime, and where framework-only knowledge runs out.
- Strong answer: Explains the queue, distinguishes microtasks from macrotasks, and can predict the order of a mixed example.
- Warning sign: Uses async and await without any model of what is happening underneath.
Closures
Underpins modules, callbacks, hooks and a whole class of memory leak.
- Strong answer: Explains variable capture, can describe a bug caused by it, and knows the connection to hooks behaviour.
- Warning sign: Cannot explain why a loop-created callback sees an unexpected value.
Equality and absent values
A daily source of defects and a reasonable proxy for defensive habits.
- Strong answer: Uses strict equality, is deliberate about null versus undefined, and does not rely on loose comparison.
- Warning sign: Uses loose equality freely, or cannot explain what it does with mixed types.
Error handling in async code
Unhandled rejections vanish silently, which is a specific and common failure.
- Strong answer: Handles rejections, understands that an unawaited promise swallows its error, and does not leave floating promises.
- Warning sign: Assumes a try block catches errors from an asynchronous call it did not await.
Module systems
Practical friction in real codebases, particularly in Node.js.
- Strong answer: Understands the difference between the two module systems and the interoperability problems that follow.
- Warning sign: Has never encountered a module resolution error, which suggests narrow exposure.
Performance and what they measured
Separates developers who have optimised from developers who have opinions.
- Strong answer: Uses the profiler, can describe a specific fix, and knows what blocks rendering.
- Warning sign: Talks about micro-optimisations with no measurement.
Dependency choices
A JavaScript project is largely other people's code.
- Strong answer: Evaluates before adding, checks what a dependency pulls in, and has removed one.
- Warning sign: Adds packages freely and has never looked at the tree.
Warning signs in a JavaScript codebase
The fastest way to read a candidate is to ask what they have found wrong in code they inherited. These are the patterns that come up most often, what they cost, and what fixing them looks like. A developer who recognises three or four of these from their own experience is worth more than one who can recite the documentation.
Floating promises
- What you see: Async functions called without being awaited or explicitly handled.
- What it costs: Errors disappear silently, ordering assumptions break, and failures surface far from their cause.
- The fix: Await or explicitly handle every promise. Enable the linter rule and treat violations as defects rather than style.
Blocking the main thread
- What you see: Heavy synchronous computation in a browser event handler.
- What it costs: The interface freezes, including scrolling and input, which users experience as the application crashing.
- The fix: Break the work up, move it to a worker, or do it on the server.
Loose equality
- What you see: Double-equals comparisons across the codebase.
- What it costs: Coercion producing comparisons that are true when nobody intended them to be.
- The fix: Use strict equality. Let the linter enforce it rather than relying on discipline.
Mutating shared objects
- What you see: Functions modifying arguments or shared state in place.
- What it costs: Action at a distance, where changing one thing breaks another with no visible connection.
- The fix: Return new values. Where mutation is necessary for performance, confine it and document why.
Dependency sprawl
- What you see: Hundreds of dependencies, several doing the same job.
- What it costs: Large bundles, slow installs, and a wide vulnerability surface nobody is tracking.
- The fix: Audit what is imported, remove what is not, and require a reason for each addition.
Console logging as the only debugging tool
- What you see: Diagnosis by inserting log statements and re-running.
- What it costs: Slow debugging, and logs left in production code.
- The fix: Use the debugger and the profiler. They answer in minutes what logging answers in hours.
What each level can own
Job titles are not comparable between companies, so it is more useful to describe levels by what a person can be left to own without supervision. These are the boundaries we use when we assess a JavaScript developer.
- Junior
- Writes features within an established framework and codebase. Needs review on async correctness and shared state.
- Mid-level
- Owns a feature including its asynchrony, error handling and tests. Can profile and debug properly.
- Senior
- Owns architecture in their area, the dependency policy, the performance budget, and can work outside the framework when required.
- Staff
- Owns cross-cutting standards: the type system approach, build tooling, shared libraries and the migration path between framework generations.
How the work is usually scoped
Team shape follows the kind of work, not the headcount you happen to have budget for. These are the shapes that come up most often and the constraint that actually governs each one.
Feature work in a modern codebase
- Usual team: One to two developers.
- What governs it: Scoped by the framework rather than the language. The language matters when something unusual is needed.
Legacy JavaScript modernisation
- Usual team: One to two developers.
- What governs it: Scoped by test coverage, which is usually absent. Characterisation tests first.
TypeScript migration
- Usual team: One senior developer to set the pattern.
- What governs it: Incremental and does not require stopping delivery.
Performance remediation
- Usual team: One senior developer, time-boxed.
- What governs it: Profiler-led. Usually bundle size and main-thread blocking.
Build tooling modernisation
- Usual team: One developer.
- What governs it: Frequently a large improvement in developer experience for modest effort.
Migration work you may actually be hiring for
A large share of JavaScript work is not new development. It is moving an existing system from one state to another while it stays in service. These are the migrations that come up most often, and each one asks for a different kind of experience from the person you hire.
JavaScript to TypeScript
- Why teams do it: Refactoring confidence and contracts at boundaries, with benefit scaling by team size.
- What to watch: File by file with both allowed in the build. Hold new files to strict settings from the start, and record each escape hatch rather than leaving it to be forgotten.
jQuery to a modern framework
- Why teams do it: Structure, testability and a hiring pool that recognises the code.
- What to watch: Incremental is possible: mount the new framework on specific elements and convert section by section. A full rewrite of a working interface is rarely the cheaper path.
CommonJS to ES modules
- Why teams do it: The standard module system, better tooling support and improved dead-code elimination.
- What to watch: Interoperability between the two is the awkward part, particularly in Node.js. Check dependencies for dual support before starting, because a single holdout can force the whole package back.
Webpack to Vite or esbuild
- Why teams do it: Substantially faster builds and a much better development loop.
- What to watch: Custom webpack configuration rarely ports directly. Projects with heavily customised builds should budget real time rather than expecting a configuration swap.
Migration work rewards a different temperament from greenfield work. The useful question in an interview is not whether someone has done the specific migration you face, but whether they have ever run one incrementally: behind a flag, with both paths live, and with a way back. Developers who have only done big-bang cutovers tend to propose them again.
What a good brief for this role contains
Most of the time lost in hiring a JavaScript developer is lost before anyone is interviewed, in the gap between what the brief says and what the team actually needs. These are the points that, for this technology specifically, change who the right candidate is. A brief that answers them can be matched in days. One that does not produces a shortlist that looks reasonable and converts badly.
- Whether the codebase is TypeScript, JavaScript, or partially migrated.
- Which framework, since that is where most day-to-day knowledge lives.
- Whether the work is browser, Node.js, or both, because these are different disciplines.
- How old the oldest code is, and whether legacy patterns are still in use.
- What the build tooling is, since modernising it is often a separate piece of work.
- Whether tests exist, because an untested JavaScript codebase changes the job considerably.
If you cannot answer some of these yet, that is normal and it is still worth writing down which ones are open. An unknown that is named can be worked around. An unknown that is papered over in a job specification turns into a rejected shortlist and a restart four weeks later.
What the US market pays for this work
JavaScript work is counted by the US Bureau of Labor Statistics under Software Developers. That classification is broader than the technology itself, so treat the figures as the shape of the market a JavaScript developer is hired into rather than as a rate card for the skill. Across the United States the Bureau counts 1,687,890 people in this occupation, with a median annual wage of $135,980.
The spread matters more than the midpoint. The 90th percentile is about 2.6 times the 10th, which is a wide band for a single occupation and tells you that the title on its own carries very little pricing information. Two people described as a JavaScript developer can sit at $82,460 and $214,670 in the same national dataset. When a budget is set from a median without asking which end of that range the work actually needs, the hire that follows is usually the wrong one in one direction or the other.
Related classifications are worth reading alongside it, because teams hiring for JavaScript frequently end up recruiting against these titles too:
| Occupation | Employed | 25th percentile | Median | 75th percentile | 90th percentile |
|---|---|---|---|---|---|
| Software Developers | 1,687,890 | $105,210 | $135,980 | $171,980 | $214,670 |
| Web Developers | 70,190 | $64,230 | $92,650 | $126,230 | $162,290 |
| Web and Digital Interface Designers | 113,330 | $73,290 | $104,000 | $158,820 | $201,550 |
Source: BLS Occupational Employment and Wage Statistics, May 2025. Figures cover all US employers and are not FuturByte rates.
These are employer-side wage figures for people on a US payroll. They exclude employer taxes, benefits, recruitment cost and the months a seat sits empty, all of which are real and none of which appear in a salary line. The useful way to read the table is as the cost of the alternative you are comparing against, not as a number to match.
How US metro markets compare for this role
The same job is priced very differently across the country. Ranked by median annual wage for Software Developers, the gap between the highest and lowest of the 28 metro areas covered here is a factor of about 1.7. San Jose sits at the top with a median of $213,110; Pittsburgh sits at the bottom with $124,500. A budget built from a national median will be wrong in both of those markets, in opposite directions.
| Metro area | Employed | Median wage | vs US median | Location quotient |
|---|---|---|---|---|
| San Jose, CA | 87,350 | $213,110 | +57% | 7.09 |
| San Francisco, CA | 69,030 | $186,640 | +37% | 2.68 |
| Seattle, WA | 92,770 | $167,280 | +23% | 4.10 |
| New York, NY | 121,000 | $166,830 | +23% | 1.17 |
| Boston, MA | 42,310 | $166,090 | +22% | 1.44 |
| San Diego, CA | 20,610 | $163,270 | +20% | 1.23 |
| Los Angeles, CA | 55,540 | $160,920 | +18% | 0.82 |
| Portland, OR | 18,260 | $156,000 | +15% | 1.39 |
| Washington, D.C. | 69,060 | $154,930 | +14% | 2.03 |
| Baltimore, MD | 16,850 | $138,900 | +2% | 1.14 |
| Denver, CO | 27,010 | $137,610 | +1% | 1.55 |
| Charlotte, NC | 20,820 | $135,920 | 0% | 1.41 |
| Chicago, IL | 40,370 | $134,380 | -1% | 0.82 |
| Austin, TX | 31,960 | $134,120 | -1% | 2.28 |
| Dallas-Fort Worth, TX | 67,030 | $133,290 | -2% | 1.52 |
| Philadelphia, PA | 28,480 | $133,040 | -2% | 0.91 |
| Atlanta, GA | 36,300 | $132,960 | -2% | 1.16 |
| Raleigh, NC | 12,580 | $132,770 | -2% | 1.56 |
| Miami, FL | 18,900 | $132,650 | -2% | 0.62 |
| Phoenix, AZ | 29,380 | $131,750 | -3% | 1.14 |
| Minneapolis-St. Paul, MN | 27,410 | $130,920 | -4% | 1.29 |
| Detroit, MI | 24,870 | $130,760 | -4% | 1.20 |
| Tampa, FL | 14,230 | $130,450 | -4% | 0.91 |
| Orlando, FL | 13,440 | $129,620 | -5% | 0.88 |
| Salt Lake City, UT | 19,040 | $129,600 | -5% | 2.12 |
| Houston, TX | 22,940 | $129,440 | -5% | 0.64 |
| Kansas City, MO | 12,160 | $124,990 | -8% | 1.02 |
| Pittsburgh, PA | 10,320 | $124,500 | -8% | 0.85 |
Location quotient compares how concentrated this occupation is in the metro against the national average. A value above 1 means the metro has more of this work than its size would predict.
The location quotient column is the more useful one for hiring. A high median tells you what a role costs; a high quotient tells you whether the people exist. San Jose, San Francisco, Seattle, Washington, D.C., Denver, Austin each have a quotient of 1.5 or above, meaning the work is concentrated there well beyond what the size of the local economy would predict. Those are the markets where a search is likely to be quick and competitive at the same time, and where a counter-offer is most likely to take a candidate off the table late in the process.
The opposite case is worth planning for too. In a metro with a low quotient, the total pool is small even when wages look reasonable, so the realistic options are to widen the search radius, accept a longer time to hire, or bring the capability in from outside the local market entirely. That last option is what most teams are weighing when they come to us.
Hiring risks worth naming
Every one of these has produced a bad hire somewhere. They are written down so that the process tests for them deliberately rather than discovering them in month three.
Framework knowledge without language depth. The most common gap. Ask about closures and the event loop directly, because frameworks hide both until they do not.
No TypeScript experience. Now the commercial default. A JavaScript-only candidate is a partial fit for most current codebases.
Habits formed before modern JavaScript. Ask what they use instead of the patterns they learned first. Some experience has not been refreshed.
Front-end experience assumed to cover Node.js. Shared language, different discipline. Test server-side concerns separately.
Hiring JavaScript developers by metro area
Wages for this occupation vary more between US metro areas than most budget models assume. Each page below sets out the published employment and wage figures for that market, how it compares with the national picture, and what the local industry mix means for the kind of JavaScript developer who will be available.
- New York, NY $166,830 median
- Seattle, WA $167,280 median
- San Jose, CA $213,110 median
- Washington, D.C. $154,930 median
- San Francisco, CA $186,640 median
- Dallas-Fort Worth, TX $133,290 median
- Los Angeles, CA $160,920 median
- Boston, MA $166,090 median
- Chicago, IL $134,380 median
- Atlanta, GA $132,960 median
- Austin, TX $134,120 median
- Phoenix, AZ $131,750 median
- Philadelphia, PA $133,040 median
- Minneapolis-St. Paul, MN $130,920 median
- Denver, CO $137,610 median
- Detroit, MI $130,760 median
- Houston, TX $129,440 median
- Charlotte, NC $135,920 median
- San Diego, CA $163,270 median
- Salt Lake City, UT $129,600 median
- Miami, FL $132,650 median
- Portland, OR $156,000 median
- Baltimore, MD $138,900 median
- Tampa, FL $130,450 median
- Orlando, FL $129,620 median
- Raleigh, NC $132,770 median
- Kansas City, MO $124,990 median
- Pittsburgh, PA $124,500 median
Frequently asked questions
Should we hire for JavaScript or for a specific framework?
For a specific framework if you have an existing codebase, because that is where the productive knowledge is. For JavaScript depth if the person will make architectural decisions or work across several frameworks. The strongest candidates have both, and between the two, language depth transfers better than framework familiarity does.
Is TypeScript now a requirement?
Close to it for commercial work. Most new projects use it, most libraries ship types, and most teams find the refactoring confidence worth the annotation cost. A candidate without TypeScript is not unhirable, and they are a partial fit for most current codebases and should be expected to pick it up quickly.
How do we test JavaScript depth rather than framework familiarity?
Ask about closures and about async ordering. Both are fundamental, both are hidden by frameworks, and neither can be answered convincingly without genuine understanding. They are far more discriminating than asking someone to build a small component.
Our JavaScript codebase has no tests. What now?
Do not start by trying to cover it. Write characterisation tests around the areas you are about to change, so you can prove behaviour is preserved, and add tests as you touch things. Attempting comprehensive coverage on a large untested codebase is a project that almost never finishes and delivers little on the way.
Why is our web application slow?
Usually bundle size or main-thread blocking. Too much JavaScript shipped means a long delay before anything is interactive; heavy synchronous work means the interface freezes during use. Both are visible in the browser profiler within minutes, and both are commonly diagnosed by guesswork instead.
Is it safe to depend on so many packages?
It is the reality of the ecosystem and it needs managing rather than avoiding. Commit lockfiles, audit on a schedule, keep upgrades continuous, and require a reason before adding a dependency that does something small. The risk is real and ordinary discipline handles most of it.
Can a front-end JavaScript developer write our Node.js back end?
They can write code that runs, and the shared language genuinely helps. What does not transfer is data modelling, transactions, failure handling and operating a service under load. Test those directly rather than assuming the language is the hard part, because it is not.
Is JavaScript still the right choice for new work?
In the browser you have no meaningful alternative, so the question is really about the server. There, JavaScript is a reasonable choice when the workload is input-and-output bound and when sharing a language and types across both halves of the product is worth something. For computation-heavy work, other runtimes will serve better.