MySQL HeatWave is the only fully managed MySQL database service that combines transactions, analytics, machine learning, and GenAI services, without ETL duplication. Also included is MySQL HeatWave Lakehouse, which allows users to query data in object storage, MySQL databases, or a combination of both. Users can deploy MySQL HeatWave–powered apps on a choice of public clouds: Oracle Cloud Infrastructure (OCI), Amazon Web Services (AWS), and Microsoft Azure. 

In MySQL 9.0, we introduced JavaScript stored programs in MySQL, bringing your custom logic closer to where your data lives. The benefits are clear: lower latency, stronger security, and reduced costs. Now we’re taking this idea a step further with LIBRARY objects. This new feature adds true modularity and code reuse to stored procedures and functions by letting you import, manage, and share JavaScript (and WebAssembly) code directly inside your MySQL database. In this article, we’ll walk through the basics with JavaScript examples to help you get started.

What Are MySQL Libraries?

As projects grow, procedural logic often becomes repetitive and difficult to maintain. LIBRARY objects solve this problem by letting you package modular pieces of code once and reuse them everywhere. They also make it simple to bring off-the-shelf code straight into your database environment.

Here’s why this matters for your technology stack:

Tap Into the JavaScript Ecosystem: Why reinvent the wheel? With LIBRARY objects, you can directly leverage thousands of open-source ECMAScript modules (ESM) and Wasm libraries right inside MySQL. This means you can:

  • Reuse popular packages or ship your own internal modules.
  • Apply existing front-end JavaScript expertise to backend data logic.
  • Stay aligned with modern development best practices.

Write Once, Use Everywhere: Define your data logic modules once, then import them into multiple stored programs. This makes your code DRY (Don’t Repeat Yourself), reduces bugs, and speeds up feature delivery, so updates roll out faster and new products reach the market sooner.

Smarter Resource Utilization: Large codebases can be expensive to manage. LIBRARY objects are designed to process and cache your code once, no matter how often it’s imported. The result:

  • No memory bloat from repeatedly loaded libraries.
  • Faster execution for complex definitions.
  • Consistent behavior across all stored programs.

How JavaScript Libraries Work in MySQL

Using MySQL Libraries with JavaScript Stored ProgramsMySQL introduces a new CREATE LIBRARY DDL statement to declare library code. For JavaScript libraries, the code needs to be a valid JavaScript ECMAScript module (ESM), this allows the user to encapsulate complex logic, export only what the user wants to expose and keep the internal machinery of the library hidden. In order to expose values (e.g. functions, constants, variables, classes, objects) the user can use default or named export mechanism. See more documentation for more details.

A LIBRARY object is not executable on its own. Once declared, it can be imported into JavaScript stored procedures or functions using the new USING clause in CREATE PROCEDURE or CREATE FUNCTION. The USING clause is equivalent to JavaScript static import. In addition to static importing, dynamic import is supported as well from within JavaScript code that can import the library dependency at runtime.

Importing Libraries aren’t limited to stored programs, Libraries can also import other libraries. This means dependency chains are supported. Libraries are cached per execution context (the same as the stored procedure or function using them). Therefore, diamond and cyclic dependencies resolve cleanly, without unexpected behavior.

Quick Walkthrough

Creating a library: Similar to creating stored program, except that no arguments can be specified. Lets take can example of a library to implement financial utility functions.

CREATE LIBRARY my_schema.finance_utils LANGUAGE JAVASCRIPT 
    AS $$
      const rates = {
        USD: 1,
        EUR: 0.88,
        GBP: 0.76,
        // Add more currency rates as needed
      };
    
      export function convertCurrency(amount, fromCurrency, toCurrency) {
        if (!(fromCurrency in rates) || !(toCurrency in rates)) {
          throw new Error('Unsupported currency');
        }
        return amount * rates[toCurrency] / rates[fromCurrency];
      }
    
      export function calculatePresentValue(futureValue, rate, time) {
        return futureValue / Math.pow((1 + rate), time);
      }
    $$;
    

Importing a library: The new USING clause is used here to import the library in two stored functions. The function is executed using a simple SELECT statement on a sample table.

CREATE FUNCTION my_schema.convert_to_usd(amount FLOAT, currency VARCHAR(4)) 
    RETURNS INT LANGUAGE JAVASCRIPT 
    USING (finance_utils)
    AS $$
      // finance_utils namespace object contains all of the exported values
      return finance_utils.convertCurrency(amount, currency, "USD")
    $$;
    
    CREATE FUNCTION my_schema.calculate_investment_present_value
    (amount FLOAT, rate FLOAT, years INT) RETURNS INT LANGUAGE JAVASCRIPT 
    USING (finance_utils AS lib)
    AS $$
      // if alias is used, the namespace object takes its name: lib
      return lib.calculatePresentValue(amount, rate, years)
    $$;
    
    CREATE TABLE investments (
      future_value FLOAT,
      currency VARCHAR(4),
      discount_rate FLOAT,
      years INT
    );
    INSERT INTO investments VALUES
    (10000.00, 'USD', 0.05, 5),
    (5000.00, 'EUR', 0.04, 3);
    
    SELECT 
      future_value,
      currency,
      convert_to_usd(future_value, currency) AS future_value_usd,
      calculate_investment_present_value(convert_to_usd(future_value, currency), 
         discount_rate, years) AS present_value_usd
    FROM investments;
    +--------------+----------+------------------+-------------------+
    | future_value | currency | future_value_usd | present_value_usd |
    +--------------+----------+------------------+-------------------+
    |        10000 | USD      |            10000 |              7835 |
    |         5000 | EUR      |             5682 |              5051 |
    +--------------+----------+------------------+-------------------+
    

Using MySQL Shell VSCode Extension: As a convenience, the VSCode extension can be used to directly import an ECMAScript module file from client file system and also provides a boilerplate code to import the LIBRARY in stored programs.

MySQL VScode Extension integration with MySQL Libraries

Securing Code

When it comes to security, LIBRARY uses the same semantics as stored programs in MySQL. All code is securely persisted in data dictionary and protected by privileged access. The code is executed in isolation i.e., two different stored programs importing the same library do not have access to each other’s resources. Existing sandboxing restrictions for JavaScript stored programs also apply to libraries. This means library code cannot perform I/O, access the file system, initiate network connections, or spawn threads. This sandboxing prevents unauthorized operations and ensures that library code cannot affect the broader server environment.

Privilege Semantics:

The privilege framework for libraries has been designed to remain consistent with that of stored programs. The CREATE ROUTINE and ALTER ROUTINE privileges now apply to libraries as well. When a library is imported into a stored program, it inherits the same security context (INVOKER) as the importing routine. In addition to the usual EXECUTE privilege required for functions and procedures, the same privilege must now also be granted on each imported library. This provides administrators with fine-grained control over which libraries are available for use within stored programs.

MySQL Library Privilege Semantics

Import Path:

Importing in JavaScript requires a path, since direct file system access is restricted, the import path is based on schema and library name. This redirects the JavaScript module loader to load the code from MySQL data dictionary (after taking privileges into account). For example, in the same example can be implemented via dynamic import inside the JavaScript code instead of USING clause in CREATE statement. Note the path reflects the schema and library name. 

CREATE FUNCTION my_schema.calculate_investment_present_value
    (amount FLOAT, rate FLOAT, years INT) RETURNS INT LANGUAGE JAVASCRIPT 
    AS $$
      let lib = await import(`/my_schema/finance_utils`)
      return lib.calculatePresentValue(amount, rate, years)
    $$;
    

Similarly, below we extend a LIBRARY to add more functionality, LIBRARY can also use static and dynamic import in its implementation inside the JavaScript code.

CREATE LIBRARY my_schema.risk_calculations LANGUAGE JAVASCRIPT 
    AS $$
      import * as lib from "/my_schema/finance_utils";
    
      export var baseCurrency = "USD";
    
      export function standardDeviation(returns) {
        const n = returns.length;
        if (n <= 1) return 0;
    
        const mean = returns.reduce((sum, value) => sum + value, 0) / n;
        const squaredDiffs = returns.map(value => Math.pow(value - mean, 2));
        const variance = squaredDiffs.reduce((sum, value) => sum + value, 0) / (n - 1);
    
        return Math.sqrt(variance);
      }
    
      export function standardDeviationInBaseCcy(returns, currency) {
        const baseCcyReturns = returns.map(r => 
          lib.convertCurrency(r, currency, baseCurrency));
        return standardDeviation(baseCcyReturns);
      }
    
      // also, re-export all the functions from original library
      export * from "/my_schema/finance_utils";
    $$;
    

Summary

With MySQL LIBRARY objects, we’ve eliminated one of the biggest pain points in stored program development: duplicated logic and hard-to-maintain code. By enabling modular, reusable JavaScript and WebAssembly code directly inside the database, you can tap into the broader ecosystem of packages, reduce bugs, simplify updates, and ship features faster, all while benefiting from MySQL’s built-in security and efficient execution model. The result is a cleaner, more powerful way to build applications with MySQL, turning your database into not just a place to store data, but a true platform for modern data processing logic.

Learn More

For more details, check the following documentation:

Try it out!