Worker: Worker() constructor

Baseline Widely available *

This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.

* Some parts of this feature may have varying levels of support.

Note: This feature is available in Web Workers, except for Service Workers.

Warning: This script passed to the url element is executed. APIs like this are known as injection sinks, and are potentially a vector for cross-site scripting (XSS) attacks.

You can mitigate this risk by having a Content Security Policy (CSP) that restricts the locations from which scripts can be loaded, and by always assigning TrustedScriptURL objects instead of strings and enforcing trusted types. See Security considerations for more information.

The Worker() constructor creates a Worker object that executes the classic script or module at the specified URL.

Syntax

js
new Worker(url)
new Worker(url, options)

Parameters

url

A TrustedScriptURL object or a string representing the URL of the script or module that the worker will execute.

This must be same-origin with the caller's document, or a blob: or data: URL. The URL is resolved relative to the current HTML page's location.

options Optional

An object containing option properties that can be set when creating the object instance. Available properties are as follows:

credentials

A string specifying whether the browser sends credentials when importing modules into a module worker. The allowed values are the same as can be passed to the fetch() request: omit, same-origin, or include. The default is same-origin (only include credentials for same-origin requests).

This is ignored for classic workers.

name

A string specifying an identifying name for the DedicatedWorkerGlobalScope representing the scope of the worker, which is mainly useful for debugging purposes.

type

A string specifying the type of worker to create. The value can be classic or module. The default is classic.

Exceptions

NetworkError DOMException

Thrown if the MIME type of the worker script is incorrect. It should always be text/javascript (for historical reasons other JavaScript MIME types may be accepted).

SecurityError DOMException

Thrown if the document is not allowed to start workers, e.g., if the URL has an invalid syntax or if the same-origin policy is violated.

SyntaxError DOMException

Thrown if url cannot be parsed.

TypeError

Thrown if the url parameter is a string when Trusted Types are enforced by a CSP and no default policy is defined.

Description

The Worker() constructor creates a Worker object that executes the classic script or module at the specified URL.

The script must be same-origin with the associated document, but may itself import scripts or modules that are cross-origin (if permitted by CORS and other restrictions). If a cross-origin worker is required, users must load it from an intermediate same-origin worker or a blob.

Module and classic workers

A classic worker is one that is constructed from a classic script, while a module worker is constructed from an ECMASCript module. The type of worker affects the worker constructor options, how the worker script is fetched, and how it is executed.

The code below shows two ways you can construct a classic worker, and also how you specify the type of "module" to create a module worker. In both cases the script must be same-origin with the loading document and is resolved relative to the location of the launching document.

js
// Construct a classic worker
const worker1 = new Worker("worker_classic.js");
const worker2 = new Worker("worker_classic.js", {
  type: "classic",
});

// Construct a module worker
const worker3 = new Worker("worker_module.js", {
  type: "module",
});

Module workers and their dependencies are loaded and executed using ECMAScript module semantics:

  • Dependencies are imported via static import statements
  • Fetched asynchronously using CORS.
  • All modules are resolved before any code is executed
  • Must be served with the media type Content-Type: text/javascript
  • Executed in Strict mode

Classic workers are fetched and executed as scripts:

Importing scripts or modules

Module workers can import ECMASCript modules using import statements. Modules are fetched using CORS, so cross-origin modules must be served with the Access-Control-Allow-Origin header in order to be loaded. Developers can specify whether or not credentials should be sent in cross-origin imports.

Classic workers can import scripts (but not modules) using the WorkerGlobalScope.importScripts() method. Unlike modules, scripts are fetched in no-cors mode, and can be requested cross-origin even if the server does not set the appropriate CORS headers. Credentials are sent for same-origin imports, but are usually not sent for cross-origin requests.

In addition, if the document has a Content Security Policy (CSP), it must allow the origins of imported scripts or modules. For modules the allowed sources are specified in worker-src (with fallback to script-src and default-src directives), while for classic scripts the sources are specified in script-src (with fallback to the default-src directives).

data: and blob: URLs

data: URLs can be passed to the url parameter, but have an opaque_origin, which makes them cross-origin to all other origins including their owner.

Consequently, while the worker can still communicate with its owner using postMessage(), it's access to other external resources is highly restricted. For example, a worker fetch() request would be cross-origin to its own site, and any requests to any origin must be granted by CORS.

blob: URLs should be used instead, where possible, because the URL inherits the origin of the document that created it. This ensures that a worker created with a blob: URL is same-origin with the page that created it. Note that if you're using a Content Security Policy (CSP) to restrict what resources can be loaded into your worker, you will need to allow the blob: origin.

Bundler considerations

Bundlers such as webpack, Vite, and Parcel, recommend passing URLs that are relative to import.meta.url to the Worker() constructor.

For example:

js
const myWorker = new Worker(new URL("worker.js", import.meta.url));

This makes the path relative to the current script instead of the current HTML page, which allows the bundler to safely do optimizations like renaming (because otherwise the worker.js URL may point to a file not controlled by the bundler, so it cannot make any assumptions).

Security considerations

The script or module specified by the url argument is executed in the web worker context, and may itself import other same-origin and cross-origin scripts. If the url is provided by a user, this is a possible vector for cross-site scripting (XSS) attacks.

While web workers do not have direct access to the owning document or window, it is still extremely risky to accept and execute arbitrary URLs from untrusted origins. For module workers, but not classic workers, CORS will control what cross-origin resources can be requested.

A website should also control what scripts that are allowed to run using a Content Security Policy (CSP) with the worker-src directive (or a fallback to child-src, script-src, or default-src). This can restrict scripts to those from the current origin, or a specific set of origins, or even particular files.

If you're using this property and enforcing trusted types (using the require-trusted-types-for CSP directive), you will need to always assign TrustedScriptURL objects instead of strings. This ensures that the input is passed through a transformation function, which has the chance to reject or modify URLs needed by the worker before they are fetched.

Examples

For brevity, only the first example below uses trusted types. In production your code should always use trusted types when passing data originating from users into injection sinks.

Using Trusted Types

To mitigate the risk of XSS, we should always pass TrustedScriptURL instances to the worker URL instead of strings. We also need to do this if we're enforcing trusted types for other reasons and we want to allow some sources that have been permitted (by CSP: worker-src).

Trusted types are not yet supported on all browsers, so first we define the trusted types tinyfill. This acts as a transparent replacement for the trusted types JavaScript API:

js
if (typeof trustedTypes === "undefined")
  trustedTypes = { createPolicy: (n, rules) => rules };

Next we create a TrustedTypePolicy that defines a createScriptURL() method for transforming input strings into TrustedScriptURL instances.

For the purpose of this example we'll assume that we want to allow a predefined set of URLs in the workerScriptAllowList array and log any other scripts.

js
const workerScriptAllowList = [
  // Some list of allowed URLs
];
const policy = trustedTypes.createPolicy("worker-url-policy", {
  createScriptURL(input) {
    if (workerScriptAllowList.includes(input)) {
      return input; // allow the script
    }
    console.log(`Script not in workerScriptAllowList: ${input}`);
    return ""; // Block the script
  },
});

Next we use our policy object to create a trustedScriptURL object from a potentially unsafe input string and pass this to the worker.

js
// The potentially malicious worker URL
// We won't be including untrustedScript in our workerScriptAllowList array
const untrustedScriptURL = "https://evil.example.com/naughty.js";

// Create a TrustedScriptURL instance using the policy
const trustedScriptURL = policy.createScriptURL(untrustedScriptURL);

// Construct the worker with the trusted URL
const myWorker = new Worker(trustedScriptURL);

Creating a classic worker

The following code snippet shows creation of a classic Worker object using the Worker() constructor, and subsequent usage of the object:

js
const myWorker = new Worker("worker.js");
const first = document.querySelector("input#number1");

first.onchange = () => {
  myWorker.postMessage(first.value);
  console.log("Message posted to worker");
};

For a full example, see our Basic dedicated worker example (run dedicated worker).

Loading a cross-origin module worker from a blob

This example shows a method that can fetch and load a cross-origin module worker script and then load it into your worker as a blob (a classic script could be loaded in the same way):

js
async function loadWorker() {
  const response = await fetch("https://other_origin.com/worker.js");
  const script = await response.text();

  // Create a blob that contains the fetched script, and then create a URL from that blob
  const blob = new Blob([script], { type: "application/javascript" });
  const workerUrl = URL.createObjectURL(blob);

  try {
    const worker = new Worker(workerUrl, { type: "module" });
  } catch (e) {
    console.error(`Cross-origin worker module failed to load: ${e}`);
  }
}
loadWorker();

The initial fetch is made with CORS, and so the other_origin.com response will need to include the Access-Control-Allow-Origin header as shown:

http
Access-Control-Allow-Origin "https://my_origin.com"

In addition, if you're using a CSP you will need to allow the blob: origin for worker-src so that it can be loaded into the document:

http
Content-Security-Policy worker-src 'self' https://other_origin.com blob:

Specifications

Specification
HTML
# dom-worker-dev

Browser compatibility

desktop mobile server
Chrome
Edge
Firefox
Opera
Safari
Chrome Android
Firefox for Android
Opera Android
Safari on iOS
Samsung Internet
WebView Android
WebView on iOS
Bun
Deno
Node.js
Worker() constructor
Chrome – Full support
Chrome 4 (Release date: 2010-01-25)
footnote Full support
Edge – Full support
Edge 12 (Release date: 2015-07-29)
footnote Full support
Firefox – Full support
Firefox 3.5 (Release date: 2009-06-30)
footnote Full support
Opera – Full support
Opera 10.6 (Release date: 2010-07-01)
footnote Full support
Safari – Full support
Safari 4 (Release date: 2009-06-08)
footnote Full support
Chrome Android – Full support
Chrome Android 18 (Release date: 2012-06-27)
footnote Full support
Firefox for Android – Full support
Firefox for Android 4 (Release date: 2011-03-29)
footnote Full support
Opera Android – Full support
Opera Android 11 (Release date: 2011-03-22)
footnote Full support
Safari on iOS – Full support
Safari on iOS 5 (Release date: 2011-10-12)
footnote Full support
Samsung Internet – Full support
Samsung Internet 1 (Release date: 2013-04-27)
footnote Full support
WebView Android – Full support
WebView Android 4.4 (Release date: 2013-12-09)
footnote Full support
WebView on iOS – Full support
WebView on iOS 5 (Release date: 2011-10-12)
footnote Full support
Bun – Full support
Bun 1 (Release date: 2023-09-08)
footnote Full support
Deno – Full support
Deno 1 (Release date: 2020-05-13)
footnote Full support
Node.js – Partial support
Node.js 11.7 (Release date: 2019-01-18)
footnote Partial support
footnote Takes entirely different options parameters.
Support for ECMAScript modules
Chrome – Full support
Chrome 80 (Release date: 2020-02-04)
footnote Full support
Edge – Full support
Edge 80 (Release date: 2020-02-07)
footnote Full support
Firefox – Full support
Firefox 114 (Release date: 2023-06-06)
footnote Full support
Opera – Full support
Opera 67 (Release date: 2020-03-03)
footnote Full support
Safari – Full support
Safari 15 (Release date: 2021-09-20)
footnote
footnote Nested workers support was introduced in Safari 15.5.
footnote Script loading in nested workers was introduced in Safari 16.4.
Chrome Android – Full support
Chrome Android 80 (Release date: 2020-02-04)
footnote Full support
Firefox for Android – Full support
Firefox for Android 114 (Release date: 2023-06-06)
footnote Full support
Opera Android – Full support
Opera Android 57 (Release date: 2020-03-30)
footnote Full support
Safari on iOS – Full support
Safari on iOS 15 (Release date: 2021-09-20)
footnote
footnote Nested workers support was introduced in Safari on iOS 15.5.
footnote Script loading in nested workers was introduced in Safari on iOS 16.4.
Samsung Internet – Full support
Samsung Internet 13 (Release date: 2020-12-02)
footnote Full support
WebView Android – Full support
WebView Android 80 (Release date: 2020-02-04)
footnote Full support
WebView on iOS – Full support
WebView on iOS 15 (Release date: 2021-09-20)
footnote
footnote Nested workers support was introduced in WebView on iOS 15.5.
footnote Script loading in nested workers was introduced in WebView on iOS 16.4.
Bun – No support
Bun
footnote No support
Deno – Full support
Deno 1 (Release date: 2020-05-13)
footnote Full support
Node.js – Partial support
Node.js 12.17 (Release date: 2020-05-26)
footnote Partial support
footnote ECMAScript modules are enabled for files ending with .mjs and for files ending with .js when the nearest parent package.json file contains a top-level field "type" with a value of "module".
Requires url parameter to be TrustedScriptURL instance when trusted types are enforced
Chrome – Full support
Chrome 97 (Release date: 2022-01-04)
footnote Full support
Edge – Full support
Edge 97 (Release date: 2022-01-06)
footnote Full support
Firefox – Preview support
Firefox Nightly
footnote Preview browser support
Opera – Full support
Opera 83 (Release date: 2022-01-19)
footnote Full support
Safari – Full support
Safari 26 (Release date: 2025-09-15)
footnote Full support
Chrome Android – Full support
Chrome Android 97 (Release date: 2022-01-04)
footnote Full support
Firefox for Android – No support
Firefox for Android
footnote No support
Opera Android – Full support
Opera Android 68 (Release date: 2022-03-30)
footnote Full support
Safari on iOS – Full support
Safari on iOS 26 (Release date: 2025-09-15)
footnote Full support
Samsung Internet – Full support
Samsung Internet 18 (Release date: 2022-08-08)
footnote Full support
WebView Android – Full support
WebView Android 97 (Release date: 2022-01-04)
footnote Full support
WebView on iOS – Full support
WebView on iOS 26 (Release date: 2025-09-15)
footnote Full support
Bun – No support
Bun
footnote No support
Deno – No support
Deno
footnote No support
Node.js – No support
Node.js
footnote No support
Strict MIME type checks for worker scripts
Chrome – No support
Chrome
footnote
footnote See bug 40554522
Edge – No support
Edge
footnote
footnote See bug 40554522
Firefox – Full support
Firefox 81 (Release date: 2020-09-22)
footnote Full support
Opera – No support
Opera
footnote
footnote See bug 40554522
Safari – Full support
Safari 16 (Release date: 2022-09-12)
footnote Full support
Chrome Android – No support
Chrome Android
footnote
footnote See bug 40554522
Firefox for Android – Full support
Firefox for Android 81 (Release date: 2020-09-22)
footnote Full support
Opera Android – No support
Opera Android
footnote
footnote See bug 40554522
Safari on iOS – Full support
Safari on iOS 16 (Release date: 2022-09-12)
footnote Full support
Samsung Internet – No support
Samsung Internet
footnote
footnote See bug 40554522
WebView Android – No support
WebView Android
footnote
footnote See bug 40554522
WebView on iOS – Full support
WebView on iOS 16 (Release date: 2022-09-12)
footnote Full support
Bun – No support
Bun
footnote No support
Deno – No support
Deno
footnote No support
Node.js – No support
Node.js
footnote No support
options.name parameter
Chrome – Full support
Chrome 70 (Release date: 2018-10-16)
footnote Full support
Edge – Full support
Edge 18 (Release date: 2018-10-02)
footnote Full support
Firefox – Full support
Firefox 55 (Release date: 2017-08-08)
footnote Full support
Opera – Full support
Opera 57 (Release date: 2018-11-28)
footnote Full support
Safari – Full support
Safari 12.1 (Release date: 2019-03-25)
footnote Full support
Chrome Android – Full support
Chrome Android 70 (Release date: 2018-10-17)
footnote Full support
Firefox for Android – Full support
Firefox for Android 55 (Release date: 2017-08-08)
footnote Full support
Opera Android – Full support
Opera Android 49 (Release date: 2018-12-07)
footnote Full support
Safari on iOS – Full support
Safari on iOS 12.2 (Release date: 2019-03-25)
footnote Full support
Samsung Internet – Full support
Samsung Internet 10 (Release date: 2019-08-22)
footnote Full support
WebView Android – Full support
WebView Android 70 (Release date: 2018-10-17)
footnote Full support
WebView on iOS – Full support
WebView on iOS 12.2 (Release date: 2019-03-25)
footnote Full support
Bun – No support
Bun
footnote No support
Deno – Full support
Deno 1 (Release date: 2020-05-13)
footnote Full support
Node.js – No support
Node.js
footnote No support
options.type parameter
Chrome – Full support
Chrome 80 (Release date: 2020-02-04)
footnote Full support
Edge – Full support
Edge 80 (Release date: 2020-02-07)
footnote Full support
Firefox – Full support
Firefox 114 (Release date: 2023-06-06)
footnote Full support
Opera – Full support
Opera 67 (Release date: 2020-03-03)
footnote Full support
Safari – Full support
Safari 15 (Release date: 2021-09-20)
footnote Full support
Chrome Android – Full support
Chrome Android 80 (Release date: 2020-02-04)
footnote Full support
Firefox for Android – Full support
Firefox for Android 114 (Release date: 2023-06-06)
footnote Full support
Opera Android – Full support
Opera Android 57 (Release date: 2020-03-30)
footnote Full support
Safari on iOS – Full support
Safari on iOS 15 (Release date: 2021-09-20)
footnote Full support
Samsung Internet – Full support
Samsung Internet 13 (Release date: 2020-12-02)
footnote Full support
WebView Android – Full support
WebView Android 80 (Release date: 2020-02-04)
footnote Full support
WebView on iOS – Full support
WebView on iOS 15 (Release date: 2021-09-20)
footnote Full support
Bun – No support
Bun
footnote No support
Deno – Full support
Deno 1 (Release date: 2020-05-13)
footnote
footnote Only supports module
Node.js – No support
Node.js
footnote No support

Legend

Tip: you can click/tap on a cell for more information.

Full support
Full support
Partial support
Partial support
In development. Supported in a pre-release version.
In development. Supported in a pre-release version.
No support
No support
See implementation notes.

See also