JavaScript
Deephaven's Open API provides an interface for external applications to access and present data, both through creating new queries or using existing ones. This guide describes how to use the JavaScript API to connect to Deephaven, discover tables, display data, and apply operations like sorting and filtering.
For a hands-on introduction with a complete, runnable example, see the JavaScript Crash Course. For detailed API reference, see the JavaScript API docs.
Key concepts
Before working with the Deephaven JavaScript API, you should understand some foundational web development concepts and how Deephaven's architecture works.
Web development prerequisites
The Deephaven JavaScript API relies on standard web technologies:
- Promise — A fluent callback API in modern browsers. Most Deephaven API methods that communicate with the server return Promises, allowing you to handle asynchronous operations with
.then()orasync/await. - WebSocket — An outgoing TCP socket connection that can be created by JavaScript code in modern browsers. Deephaven uses WebSockets for real-time communication between your application and the server.
- Web Worker — A distinct JavaScript process without access to the DOM, allowing work to be done in the background. The Deephaven API uses Web Workers to handle server messages without blocking your UI.
Deephaven architecture
A Deephaven Enterprise installation consists of several servers that your JavaScript client interacts with:
- Authentication server — Handles authentication and authorization.
- PQ Controller — Manages Persistent Queries and their configuration.
- Configuration server — Manages most Deephaven server configuration.
- Remote Query Dispatcher — Manages workers as needed.
- Remote Query Processor (worker) — Performs queries as requested by Persistent Queries or client consoles.
- Web API Service — Serves the Web IDE, hosts
connection.jsonfor service discovery, and proxies Web IDE connections to backend services.
When you connect via the JavaScript API, you authenticate once, and the API automatically manages Auth Tokens for connections to other servers. You don't need to manually handle token exchanges between servers.
How tables work
Deephaven tables have some important characteristics:
- Table configuration is immutable — Sorting, filtering, or adjusting columns creates a new table rather than modifying the existing one. The API handles this transparently.
- Viewport-based data loading — Table metadata (size, columns, sorts, filters) is kept up to date automatically, but actual table data only loads when you call
setViewport. - Two table types — Preemptive tables always send all contents to the client. Non-preemptive tables let you specify which rows and columns you want updates for.
Column types
Each column in a Deephaven table has a type property indicating the Java type of its data. When you read values with row.get(column), the API converts them to appropriate JavaScript types:
- String — Returned as JavaScript strings.
- Number types (int, long, double, etc.) — Returned as JavaScript numbers. Note that JavaScript numbers have limited precision, so very large long values may lose precision.
- Boolean — Returned as JavaScript booleans.
- DateTime — Deephaven uses nanosecond precision internally. Values are returned as opaque wrapper objects that support
toString,valueOf,asNumber(nanoseconds), andasDate(JavaScript Date in milliseconds).
When creating filter values, use the appropriate factory method to ensure type correctness:
FilterValue.ofString(value)— For string comparisons.FilterValue.ofNumber(value)— For numeric comparisons, including DateTime values.FilterValue.ofBoolean(value)— For boolean comparisons.
Connection and reconnection
The API provides events to monitor connection state:
connect— Fired when the initial connection is established.disconnect— Fired when the connection is lost. Some messages may be delayed until reconnection.reconnect— Fired when the client automatically reconnects to the server.
The API handles reconnection automatically. You don't need to manually reconnect, but you should listen for these events to update your UI appropriately (for example, showing a "reconnecting" indicator).
Error handling
Errors are communicated through requestfailed events on various objects:
- Client — Errors communicating with the main server.
- QueryInfo — Errors communicating with a specific worker.
- Table — Errors during table operations. Recent operations may have failed and need to be reapplied.
Listen for these events to handle errors gracefully:
Performance considerations
To keep your application responsive and minimize server load:
- Reuse sort and filter objects — When possible, reuse existing
SortandFilterConditioninstances rather than creating new ones. The server can optimize operations when it recognizes previously applied sorts and filters. - Close unused tables — Call
table.close()when you're done with a table to free server resources. - Don't retain
Rowobjects —Rowobjects may be pooled or discarded internally. Always request fresh viewport data rather than caching rows. - Size viewport appropriately — Request only the rows you need to display. You can specify an
updateIntervalMsparameter to control how often the server sends updates (default is one second). - Use subscriptions carefully — Full table subscriptions via
table.subscribecan be expensive for large tables. Prefer viewport-based access withsetViewportwhen possible.
Deephaven glossary
- Auth Token — An identifier from the Authentication server that allows a client to connect to a server and make requests. Tokens are single-use and expire after a configurable period (default is 5 minutes).
- Open API — Allows access to Deephaven data without using Deephaven's own client.
- Persistent Query — A scripted query running on a worker, available to multiple users, and manageable through the PQ Controller.
- Query Config — Describes a Persistent Query, the script running on it, and the tables it makes available to users.
- Reconnection Token — A signed identifier that allows a client to reconnect without providing credentials again. Must be periodically refreshed.
- Table Definition — Metadata for a table, describing the columns and their types.
Loading the library
The JavaScript library is tied to the version of the server it connects to, so you typically load it from the server itself. The library resides at /irisapi/irisapi.nocache.js on the web server.
Include this script tag in your HTML file, replacing https://your-deephaven-server/ with your actual server URL:
Connecting and authenticating
To connect to Deephaven, create a dh.Client instance, wait for the connect event, then call login. The following example uses password authentication. Deephaven supports multiple authentication methods — see Authentication for other options like SAML and LDAP.
The login method takes an object with three properties:
username— Your Deephaven username.token— Your authentication credential (password, SSO token, etc.).type— The authentication method to use. This must match an auth handler configured on your server.
After authentication, the API automatically manages WebSocket connections and token refreshes. You only need to add callbacks to Promises as needed.
Discovering Persistent Queries
Persistent Queries are collections of tables running on workers. You can discover available queries and subscribe to changes as they're added, removed, or updated.
The following example shows how to retrieve all known Persistent Queries and listen for changes:
The queryInfo object contains:
name— The Persistent Query's display name.serial— A unique identifier for this query instance.designated— The designated replica (undefined if the query is not running).designated.objects— An array of objects withnameandtypeproperties (e.g.,Table,TreeTable,Figure).designated.getTable(name)— A method to retrieve a specific table.
Opening and displaying tables
Connecting to a table can be expensive, so the API uses a lazy loading pattern. The TableSelector class (used by addTable above) stores a reference to the query and table name, then loads the table only when the user clicks. Once loaded, it creates a TableView to display the data.
The following example shows the TableSelector and TableView classes that complete the flow:
Key points:
setViewport(startRow, endRow, columns)— Tells the server which rows and columns you want. Data arrives via theupdatedevent.addEventListener— Returns a cleanup function. Call it to stop receiving updates.table.columns— Contains column metadata including names and types.row.get(column)— Retrieves the value for a specific column in a row.
Sorting and filtering
You can extend the TableView class (defined above) with methods to sort and filter data. The table's applySort and applyFilter methods apply the new configuration and return the previously applied sorts or filters (not Promises). The actual data update happens asynchronously — listen for sortchanged, filterchanged, or updated events, or call getViewportData() to wait for new data.
Add these methods to your TableView class:
Example usage
Cloning tables
Use table.copy when you want to apply different sorts or filters without affecting the original table. Each copy:
- Fires its own events.
- Maintains its own viewport.
- Must be closed independently with
table.close().
Server operation order
The applySort, applyFilter, and setViewport methods are synchronous setters that queue operations to be processed on the server. The server processes these operations in order, but the methods return immediately — you may continue receiving updates with the old sort/filter until the server applies the change.
To know when a change has taken effect:
- Events — Listen for
sortchanged,filterchanged, orupdatedevents. - Promise — Call
getViewportData()to get a Promise that resolves with the next viewport update.
Caution
When you change the sort or filter, the current viewport is cleared. You must set a new viewport after each sort or filter change.
When applying a single change, set the viewport immediately after:
When applying multiple changes, set the viewport only after the last change:
Connecting to Core+ queries
Core+ queries use a different protocol than standard Enterprise queries. To work with Core+ tables, you need to dynamically load the Core+ API and create a separate authenticated connection.
The following example shows an extended TableSelector that handles both Enterprise and Core+ queries. Use this version instead of the simpler TableSelector above if your deployment includes Core+ workers:
The Core+ connection flow:
- Check the protocol — Query
workerKindsto see if the query supports theCommunityprotocol. - Load the API — Dynamically import the Core+ API from
queryInfo.designated.jsApiUrl. - Authenticate — Create an auth token via
enterpriseClient.createAuthTokenand use it to log in to the Core+ client. - Get the connection — Call
getAsIdeConnectionto get an IDE-like connection. - Fetch the table — Use
connection.getObjectwith the table name and type.
API design principles
The Deephaven JavaScript API is designed to give web developers a familiar experience:
- Automatic connection management — After logging in, Auth Tokens are maintained automatically. Connections to other servers happen transparently.
- Mutable table interface — While tables are immutable on the server, the API lets you treat them as mutable objects. It tracks server-side tables internally and creates new ones as needed.
- Simple size tracking — Total table size is exposed through a property rather than requiring you to track changes across messages.
- Cell-level formatting — Format information is available as additional detail on each cell, not as hidden columns.
- Non-blocking operations — Most server communication happens via Web Workers, keeping your UI responsive. Methods that communicate with the server return Promises or fire events.