2 MLE JavaScript Modules and Environments

A JavaScript module is a unit of MLE's language code stored in the database as a schema object.

Storing code within the database is one of the main benefits of using JavaScript in MLE: rather than having to manage a fleet of application servers each with their own copy of the application, the database takes care of this for you.

In addition, Data Guard replication ensures that the same code is present in both production and all physical standby databases. Configuration drift, a common problem bound to occur when invoking the disaster recovery location, can be mitigated against.

A JavaScript module in MLE is equivalent to an ECMAScript 6 module. The terms MLE module and JavaScript module are used interchangeably. The contents are specific to JavaScript and can be managed using Data Definition Language (DDL) commands.

In traditional JavaScript environments, additional information is often passed to the runtime using directives or configuration scripts. In MLE, this can be achieved using MLE environments, an additional metadata structure complementing MLE modules. MLE environments are also used for name resolution of JavaScript module imports. Name resolution is crucial for maintaining code and separating it into various modules to be used with MLE.

See Also:

Developer.mozilla.org for more information about JavaScript modules


Using JavaScript Modules in MLE

JavaScript modules can be used in several different ways and can be managed using a set of Data Definition Language (DDL) commands.

JavaScript code provided in MLE modules can be used in the following ways:

  • JavaScript functions exported by an MLE modules can be published by creating a call specification known as an MLE module call. This allows the function to be called directly from SQL and PL/SQL.

  • Functionality exported by a JavaScript MLE module can be imported in other MLE JavaScript modules.

  • Code snippets in DBMS_MLE can import modules for dynamic invocation of JavaScript.

Before a user can create and execute MLE modules, several privileges must be granted.

See Also:


Managing JavaScript Modules in the Database

SQL allows the creation of MLE modules as schema objects, assuming the necessary privileges are in place.

At a minimum, you need the CREATE MLE MODULE privilege to create or replace an MLE module in your own schema. Additionally, you must have the execute privilege on the target JavaScript language object.

See Also:


Naming JavaScript Modules

Each JavaScript module name must be unique in the schema that it is created in. Unless a fully qualified name is used, the current user's schema is used.

As with other schema object identifiers, the module name is case-sensitive if enclosed in double quotation marks. If the enclosing quotation marks are omitted, the name is implicitly converted to uppercase.

When choosing a unique name, note that MLE objects share the namespace with tables, views, materialized views, sequences, private synonyms, PL/SQL packages, functions, procedures, and cache groups.

Creating JavaScript Modules in the Database

JavaScript modules are created in the database using the CREATE MLE MODULE DDL statement, specifying name and source code of the MLE module.

As soon as an MLE module has been created, it is persisted in the database dictionary. This is one of the differences when compared to dynamic execution of JavaScript code using DBMS_MLE.

CREATE MLE MODULE (without the OR REPLACE clause) throws an error if an MLE module with the given name already exists. With CREATE OR REPLACE MLE MODULE, the existing module is replaced if it exists, otherwise a new one is created. When an MLE module is replaced, privileges to it do not need to be re-granted.

For those who are familiar with PL/SQL, note that this is exactly the same behavior experienced with PL/SQL program units.

If you do not wish to replace an existing module in the event the module name is already in use, you can use the IF NOT EXISTS clause rather than CREATE OR REPLACE. The syntax for this variation is shown in Example 2-1. The IF NOT EXISTS and OR REPLACE clauses are mutually exclusive.

See Also:

Oracle Database Development Guide for more information about using the IF [NOT] EXISTS syntax

Example 2-1 Creating a JavaScript Module in the Database

This example demonstrates the creation of an MLE module and the export of a simple JavaScript function.


* get the value of all line items in an order
* @param {array} lineItems - all the line items in a purchase order
* @returns {number} the total value of all line items in a purchase order
export function orderValue(lineItems) {
    return lineItems
        .map( x => x.Part.UnitPrice * x.Quantity )
            (accumulator, currentValue) => accumulator + currentValue, 0

The first line of this code block specifies the JavaScript module name as po_module. The remaining lines define the actual JavaScript code. Note that in line with the ECMAScript standard, the export keyword indicates the function to be exported to potential callers of the module. MLE accepts code adhering to the ECMAScript 2022 standard.

Storing JavaScript Code in Databases Using Single-Byte Character Sets

Character set standards and things to remember when using a single-byte character set with MLE.

JavaScript is encoded in Unicode. The Unicode Standard is a character encoding system that defines every character in most of the spoken languages in the world. It was developed to overcome limitations of other character-set encodings.

Oracle recommends creating databases using the AL32UTF8 character set. Using the AL32UTF8 character set in the database ensures the use of the latest version of the Unicode Standards and minimizes the potential for character-set conversion errors.

In case your database still uses a single-byte character set such as US7ASCII, WE8ISO8859-n, or WE8MSWIN1252, you must be careful not to use Unicode features in MLE JavaScript code. This is no different than handling other types of input data with such a database.

See Also:

Oracle Database Globalization Support Guide for more details about the Unicode Standard

Code Analysis

MLE does not perform any checks on JavaScript code for correctness or coding best practice. Thus, developers should use their linting tool of choice to perform analysis before executing the CREATE MLE MODULE command.

When creating MLE modules in the database, you should use a well-established toolchain in the same way other JavaScript projects are governed. In this sense, the call to CREATE MLE MODULE can be considered a deployment step, similar to deploying a server application. Code checking should be performed during a build step, for example by a continuous integration and continuous deployment (CI/CD) pipeline, prior to deployment.

It is considered an industry best practice to process code with a tool called a linter before checking it into a source-code repository. As with any other development project, you are free to choose the best option for yourself and your team. Some potential options include ESLint, JSHint, JSLint, and others that perform static code analysis to flag syntax errors, bugs, or otherwise problematic code. They can also be used to enforce a certain coding style. Many integrated development environments (IDEs) provide linting as a built-in feature, invoking the tool as soon as a file is saved to disk and flagging any issues.

In addition to executing linting dynamically, it is possible to automate the code analysis using highly automated DevOps environments to invoke linting as part of a build pipeline. This step usually occurs prior to submitting the JavaScript module to the database.

The aim is to trap as many potential issues as possible before they can produce problems at runtime. Unit tests can help further mitigate these risks and their inclusion into the development process have become an industry best practice. Regardless of the method you choose, the code analysis step occurs prior to submitting the JavaScript module to the database.

Preparing JavaScript code for MLE Module Calls

JavaScript modules in MLE follow the ECMAScript 6 standard for modules. Functions and variables expected to be consumed by users of the MLE module must be exported.

Those variables and functions not exported are considered private in the module. Example 2-3 demonstrates the use of both public and private functions in an MLE JavaScript module.

An ECMAScript module can import other ECMAScript modules using import statements or dynamic import calls. This functionality is present in MLE as well. Complementary metadata to MLE modules is provided in MLE environments.

Note that console output in MLE is facilitated using the console object. By default, anything written to console.log() is routed to DBMS_OUTPUT and will end up on the screen.

JavaScript code like that in Example 2-1 cannot be accessed from SQL or PL/SQL without the help of call specifications. For now, you can think of a call specification as a PL/SQL program unit (function, procedure, or package) where its PL/SQL body is replaced with a reference to the JavaScript module and function, as shown in Example 2-2. For more information about call specifications, see MLE JavaScript Functions.

Example 2-2 Create a Call Specification for a Public Function

This example uses the module po_module created in Example 2-1. A call specification for orderValue(), the only function exported in po_module, can be written as follows:

    p_line_items JSON
MLE MODULE po_module
SIGNATURE 'orderValue';

Once the function is created, it is possible to calculate the value of a given purchase order:

    order_value(po.po_document.LineItems[*]) order_value
    j_purchaseorder po;


---------- -----------
1600             279.3
672              359.5

Example 2-3 Public and Private Functions in a JavaScript Module

In addition to public (exported) functions, it is possible to add functions private to the module. In this example, the calculation of the value is taken out of the map() function and moved to a separate function (refactoring).

The first function in the following code, lineItemValue(), is considered private, whereas the second function, orderValue(), is public. The export keyword is provided at the end of this code listing but can also appear as a prefix for variables and functions, as seen in Example 2-1. Both variations are valid JavaScript syntax.


* calculate the value of a given line item. Factored out of the public 
* function to allow for currency conversions in a later step
* @param {number} unitPrice - the price of a single article
* @param {number} quantity - the quantity of articles ordered
* @returns {number} the monetary value of the line item
function lineItemValue(unitPrice, quantity) {
    return unitPrice * quantity;

* get the value of all line items in an order
* @param {array} lineItems - all the line items in a purchase order
* @returns {number} the total value of all line items in a purchase order
function orderValue(lineItems) {
    return lineItems
                .map( x => lineItemValue(x.Part.UnitPrice, x.Quantity) )
                    (accumulator, currentValue) => accumulator + currentValue, 0 

export { orderValue }

Additional Options for Providing JavaScript Code to MLE

The JavaScript source code of an MLE module can be specified inline with PL/SQL but can also be provided using a BFILE, BLOB, or CLOB, in which case the source file must be UTF8 encoded.

Creating MLE modules using the BFILE clause can cause problems with logical replication such as GoldenGate. In order for the DDL command to succeed on the target database, the same directory must exist on the target database. Furthermore, the same JavaScript file must be present in this directory. Failure to adhere to these conditions will cause the call to create the MLE module on the target database to fail.

A BLOB or a CLOB can also be used to create an MLE module as an alternative to using a BFILE. Example 2-5 shows how to create a JavaScript module using a CLOB. If you prefer to use a BLOB, the syntax is the same but the value of the BLOB will differ from that of a CLOB.

Example 2-4 Providing JavaScript Source Code Using a BFILE

In this example, JS_SRC_DIR is a database directory object mapping to a location on the local file system containing the module's source code in a file called myJavaScriptModule.js. When loading the file from the directory location, MLE stores the source code in the dictionary. Subsequent calls to the MLE module will not cause the source code to be refreshed from the disk. If there is a new version of the module stored in myJavaScriptModule.js, it must be deployed using another call to CREATE OR REPLACE MLE MODULE.

CREATE MLE MODULE mod_from_bfile
USING BFILE(JS_SRC_DIR,'myJavaScriptModule.js');

Example 2-5 Providing JavaScript Source Code Using a CLOB

CREATE OR REPLACE MLE MODULE mod_from_clob_inline
    SELECT q'~
    export function clob_hello(who){
        return `hello, ${who}`;

As an alternative, you also have the option of using JavaScript source code that is stored in a table. This example variation assumes your schema features a table named javascript_src containing the JavaScript source code in column src along with some additional metadata. The following statement fetches the CLOB and creates the module.

CREATE OR REPLACE MLE MODULE mod_from_clob_table
    SELECT src
    FROM javascript_src
        id = 1 AND 
        commit_hash = 'ac1fd40'

Staging tables like this can be found in environments where Continuous Integration (CI) pipelines are used to deploy JavaScript code to the database.

Specifying Module Version Information and Providing JSON Metadata

MLE modules may carry optional metadata in the form of a version string and free-form JSON-valued metadata.

Both kinds of metadata are purely informational and do not influence the behavior of MLE. They are stored alongside the module in the data dictionary.

The VERSION flag can be used as an internal reminder about what version of the code is deployed. The information stored in the VERSION field allows developers and administrators to identify the code in the version control system.

The format for JSON metadata is not bound to a schema; anything useful or informative can be added by the developer. In case the MLE module is an aggregation of sources created by a tool such as rollup.js or webpack, it can be useful to store the associated package-lock.json file alongside the module.

The metadata field can be used to create a software bill of material (SBOM), allowing security teams and administrators to track information about deployed packages, especially in the case where third-party modules are used.

Tracking dependencies and vulnerabilities in the upstream repository supports easier identification of components in need of update after security vulnerabilities have been reported.

See Also:

Example 2-6 Specification of a VERSION string in CREATE MLE MODULE

export function sq(num) {
  return num * num;

Example 2-7 Addition of JSON Metadata to the MLE Module

This example uses the module version_mod, created in Example 2-6.

ALTER MLE MODULE version_mod
    "name": "devel",
    "lockfileVersion": 2,
    "requires": true,
    "packages": {}

Drop JavaScript Modules

The DROP MLE MODULE DDL statement is used for dropping an MLE module.

The DROP statement specifies the name, and optionally the schema of the module to be dropped. If a schema is not specified, the schema of the current user is assumed.

Attempting to drop an MLE module that does not exist causes an error to be thrown. In cases where this is not desirable, the IF EXISTS clause can be used. The DROP MLE MODULE command is silently skipped if the indicated MLE module does not exist.

Example 2-8 Drop an MLE Module

DROP MLE MODULE unused_mod;

Example 2-9 Drop an MLE Module Using IF EXISTS


Alter JavaScript Modules

Attributes of an MLE module can be assigned or altered using the ALTER MLE MODULE statement.

The ALTER MLE MODULE statement specifies the name, and optionally the schema of the module to be altered. If the module name is not prefixed with a schema, the schema of the current user is assumed.

Example 2-10 Alter an MLE Module


Overview of Built-in JavaScript Modules

MLE provides a set of built-in JavaScript modules that are available for import in any execution context.

Built-in modules are not deployed to the database as user-defined MLE modules, but are included as part of the MLE runtime. In particular, MLE provides the following three built-in JavaScript modules:

  • mle-js-oracledb is the JavaScript MLE SQL Driver.

  • mle-js-bindings provides functionality to import and export values from the PL/SQL engine.

  • mle-js-plsqltypes provides definitions for the PL/SQL wrapper types. For example, JavaScript types that wrap PL/SQL and SQL types like OracleNumber.

  • mle-js-fetch provides a partial Fetch API polyfill, allowing developers to invoke external resources.

  • mle-encode-base64 contains code to work with base64-encoded data.

These modules can be used to interact with the database and provide type conversions between the JavaScript engine and database engine.

See Also:

Server-Side JavaScript API Documentation for more information about the built-in JavaScript modules

Dictionary Views Related to MLE JavaScript Modules

The Data Dictionary includes details about JavaScript modules.



Each JavaScript module's source code is externalized using the [USER | ALL | DBA | CDB]_SOURCE dictionary views.

Modules created with references to the file system using the BFILE operator show the code at the time of the module's creation.

For more information about *_SOURCE, see Oracle Database Reference.

Example 2-11 Externalize JavaScript Module Source Code

    name = 'PO_MODULE';

Example output:

----- -------------------------------------------------------------
    1 /**
    2  * calculate the value of a given line item. Factored out of the public
    3  * function to allow for currency conversions in a later step
    4  * @param {number} unitPrice - the price of a single article
    5  * @param {number} quantity - the quantity of articles ordered
    6  * @returns {number} the monetary value of the line item
    7  */
    8 function lineItemValue(unitPrice, quantity) {
    9     return unitPrice * quantity;
   10 }
   13 /**
   14  * get the value of all line items in an order
   15  * @param {array} lineItems - all the line items in a purchase order
   16  * @returns {number} the total value of all line items in a purchase order
   17  */
   18 export function orderValue(lineItems) {
   20     return lineItems
   21                 .map( x => lineItemValue(x.Part.UnitPrice, x.Quantity) )
   22                 .reduce(
   23                     (accumulator, currentValue) => accumulator + currentValue, 0
   24                 );
   25 }

Metadata pertaining to JavaScript MLE modules are found in [USER | ALL | DBA | CDB]_MLE_MODULES.

Any JSON metadata specified, version information, as well as language, name, and owner can be found in this view.

For more information about *_MLE_MODULES, see Oracle Database Reference.

Example 2-12 Find MLE Modules Defined in a Schema


Example output:

MODULE_NAME                    VERSION    METADATA
------------------------------ ---------- -----------

Specifying Environments for MLE Modules

MLE environments are schema objects in the database. Their functionality and management methods are described.

MLE environments complement MLE modules and allow you to do the following:

  • Set language options to customize the JavaScript runtime in its execution context

  • Enable specific MLE modules to be imported

  • Manage name resolution and the import chain


Creating MLE Environments in the Database

The SQL DDL supports the creation of MLE environments.

Just like MLE modules, MLE environments are schema objects in the database, persisted in the data dictionary.

At a minimum, you must have the CREATE MLE MODULE privilege to create or replace an MLE environment in your own schema.

See Also:


Naming MLE Environments

Each JavaScript environment's name must be unique in the schema it is created in. Unless a fully qualified name is used, the current user's schema is used.

As with other schema object identifiers, the name is case-sensitive if enclosed in double quotation marks. If the enclosing quotation marks are omitted, the name is implicitly converted to uppercase.

MLE environments cannot contain import mappings that conflict with the names of the MLE built-in modules (mle-js-oracledb, mle-js-bindings, mle-js-plsqltypes, mle-js-fetch, and mle-encode-base64). If you attempt to add such a mapping using either the CREATE MLE ENV or ALTER MLE ENV DDL, the operation fails with an error.

Creating an Empty MLE Environment

The DDL statement CREATE MLE ENV can be used to create an MLE environment.

In its most basic form, an environment can be created empty as shown in the following snippet:


Subsequent calls to ALTER MLE ENV can be used to add properties to the environment.

Just like with MLE modules, it is possible to append the OR REPLACE clause to instruct the database to replace an existing MLE environment rather than throwing an error.

Furthermore, the IF NOT EXISTS clause can be used instead of the OR REPLACE clause to prevent the creation of a new MLE environment in the case that one already exists with the same name. In this case, the statement used to create the environment changes to the following:



The IF NOT EXISTS and OR REPLACE clauses are mutually exclusive.

See Also:

Modifying MLE Environments for information about editing existing environments

Creating an Environment as a Clone of an Existing Environment

If needed, a new environment can be created as a point-in-time copy of an existing environment.

The new environment inherits all settings from its source. Subsequent changes to the source are not propagated to the clone. A clone can be created as shown in the following statement:

Using MLE Environments for Import Resolution

It is possible to import functionality exported by one JavaScript module into another using the import statement.

The separation of code allows for finer control over changes and the ability to write more reusable code. Simplified code maintenance is another positive effect of this approach.

Only those identifiers marked with the export keyword are eligible for importing.

Modules attempting to import functionality from other modules stored in the database require MLE environments in order to perform name resolution. To create an MLE environment with that information, the IMPORTS clause must be used. Example 2-13 demonstrates how a mapping is created between the identifier po_module and JavaScript module PO_MODULE, created in Example 2-1.

Multiple imports can be provided as a comma-separated list. In Example 2-13, the first parameter in single quotation marks is known as the import name. The import name is used by another module's import statement. In this case, 'po_module' is the import name and refers to the module of the same name.


The import name does not have to match the module name. Any valid JavaScript identifier can be used. The closer the import name matches the module name it refers to, the easier it is to identify the link between the two.

The CREATE MLE ENV command fails if a module referenced in the IMPORTS clause does not exist or is not accessible to you.

Built-in JavaScript modules can be imported directly without having to specify additional MLE environments.

See Also:

Overview of Built-in JavaScript Modules for more information about built-in modules

Example 2-13 Map Identifier to JavaScript Module

    'po_module' MODULE PO_MODULE

Example 2-14 Import Module Functionality

CREATE OR REPLACE MLE MODULE import_example_module
import * as po from "po_module";
* use po_module's getValue() function to calculate the value of
* a purchase order. In later chapters, when discussing the MLE
* JavaScript SQL driver the hard-coded value used as the PO will
* be replaced by calls to the database
* @returns {number} the value of all line items in the purchase order
export function purchaseOrderValue() {
    const purchaseOrder = {
        "PONumber": 1600,
        "Reference": "ABULL-20140421",
        "Requestor": "Alexis Bull",
        "User": "ABULL",
        "CostCenter": "A50",
        "ShippingInstructions": {
            "name": "Alexis Bull",
            "Address": {
                "street": "200 Sporting Green",
                "city": "South San Francisco",
                "state": "CA",
                "zipCode": 99236,
                "country": "United States of America"
            "Phone": [
                    "type": "Office",
                    "number": "909-555-7307"
                    "type": "Mobile",
                    "number": "415-555-1234"
        "Special Instructions": null,
        "AllowPartialShipment": true,
        "LineItems": [
                "ItemNumber": 1,
                "Part": {
                    "Description": "One Magic Christmas",
                    "UnitPrice": 19.95,
                    "UPCCode": 13131092899
                "Quantity": 9.0
                "ItemNumber": 2,
                "Part": {
                    "Description": "Lethal Weapon",
                    "UnitPrice": 19.95,
                    "UPCCode": 85391628927
                "Quantity": 5.0
    return po.orderValue(purchaseOrder.LineItems);
The following call specification allows you to call the purchaseOrderValue function:

CREATE FUNCTION purchase_order_value
MLE MODULE import_example_module
ENV po_env
SIGNATURE 'purchaseOrderValue';

SELECT purchase_order_value;


Providing Language Options

MLE allows the customization of JavaScript's runtime by setting language-specific options in MLE environments.

Any options specified in the MLE environment take precedence over the default settings.

Multiple language options can be provided as a comma-separated list of '<key>=<value>' strings. The following snippet demonstrates how to enforce JavaScript's strict mode.

    LANGUAGE OPTIONS 'js.strict=true';

Changes made to the language options of an environment are not propagated to execution contexts that have already been created using the environment. For changes to take effect for existing contexts, the contexts need to be dropped and recreated.


White space characters are not allowed between the key, equal sign, and value.


JavaScript Language Options

A full list of JavaScript language options available to be used with MLE are included.

Table 2-1 JavaScript Language Options

Language Option Accepted Value Type Default Description
js.strict boolean false Enforce strict mode.
js.console boolean true Provide console global property.
js.polyglot-builtin boolean true Provide Polyglot global property.

Dropping MLE Environments

MLE environments that are no longer needed can be dropping using the DROP MLE ENV command.

The following snippet demonstrates a basic example of dropping an MLE module:


As with MLE modules, the IF EXISTS clause prevents an error if the named MLE environment does not exist, as shown in the following snippet:


Modifying MLE Environments

Existing MLE environments can be modified using the ALTER MLE ENV command.

It is possible to modify language options and the imports clause.


Altering Language Options

You can modify language options provided to an MLE module.

Use the ALTER MLE ENV clause to modify language options, as shown in the following snippet:

    SET LANGUAGE OPTIONS 'js.strict=false';
Modifying Module Imports

In the context of MLE module imports, the ALTER MLE ENV command allows you to add additional imports as well as modify and drop existing imports.

Imports not specified during an environment's creation can be added to existing MLE environments using the ADD IMPORTS clause. Import names, once defined, are static and must be dropped before they can be added as desired. Assuming you have run a new CREATE MLE DDL to replace IMPORT_EXAMPLE_MODULE from Example 2-1 with the module name IMPORT_EXAMPLE_MODULE_V2, the following statement will run successfully:

    'import_example' MODULE IMPORT_EXAMPLE_MODULE_V2

Any imports no longer needed can be dropped using the DROP IMPORTS clause:

ALTER MLE ENV po_env DROP IMPORTS('import_example');

The case of the import identifier must match that in the data dictionary's USER_MLE_ENV_IMPORTS view.

Dictionary Views Related to MLE JavaScript Environments

Details about MLE environments are available in these families of views: USER_MLE_ENVS and USER_MLE_ENV_IMPORTS.

In addition to the USER prefix, these views exist in all namespaces: CDB, DBA, ALL, and USER.



The USER_MLE_ENVS view lists all MLE environments available to you along with the defined language options.

For more information about *_MLE_ENVS, see Oracle Database Reference.

Example 2-15 List Available MLE Environments Using USER_MLE_ENVS


Example SQL*Plus output:

-------------------- ---------- ----------------------
JSDEV01              MYENVOPT   js.strict=true

The [USER | ALL | DBA | CDB]_MLE_ENV_IMPORTS family of views lists imported modules.

MLE environments are the key enablers for resolving names of imported modules. Example 2-16 demonstrates a query against USER_MLE_ENV_IMPORTS to list IMPORT_NAME, MODULE_OWNER, and MODULE_NAME.

For more information about *_MLE_ENV_IMPORTS, see Oracle Database Reference

Example 2-16 List Module Import Information Using USER_MLE_ENV_IMPORTS


SQL*Plus output:

---------------------- ------------------------- ------------------