---
title: How to use Deephaven in a local development environment (Groovy)
sidebar_label: Local Query Development
---

This guide shows how to create Java or Groovy projects that use Deephaven libraries for local development and unit testing.

## Prerequisites

- Java 17 or later
- Gradle 7.3+ or Maven 3.6+
- An IDE such as IntelliJ IDEA (recommended), Eclipse, or VS Code

**Two common scenarios:**

- **Deephaven Community only** — For standalone applications, utilities, or projects that use the open-source Deephaven engine. All artifacts are available on Maven Central with no special credentials.
- **Core+ worker projects** — For code that runs inside a Core+ worker, such as custom query utilities or Persistent Query scripts. These require access to the Deephaven artifact repository.

> [!NOTE]
> Download example projects:
>
> - [Example Gradle project files](../../assets/LocalQueryDevProject.zip) (Core+)
> - [Example Maven project files](../../assets/example-maven-project.zip) (Core+)

## Set up your IDE

This guide uses IntelliJ IDEA with the Gradle build tool. Start by creating a new Java project:

![A new Java project in IntelliJ IDEA](../../assets/IJ1.png)

Your new project will include a `build.gradle` file that looks something like this:

```groovy
plugins {
    id 'groovy'
    id 'java-library'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
   implementation 'org.codehaus.groovy:groovy-all:3.0.9'
   testImplementation platform('org.junit:junit-bom:5.10.0')
   testImplementation 'org.junit.jupiter:junit-jupiter'
}

test {
    useJUnitPlatform()
}
```

> [!TIP]
> The dependency versions shown are examples. Update them as appropriate for your project.

## Deephaven Community projects

For standalone projects using only the open-source Deephaven engine, add the dependencies you need from Maven Central. No special repository or credentials are required.

### Gradle

```groovy
def dhcVersion = 'VAR::COREPLUS_DHC_VERSION'

dependencies {
    // Core table API and implementations
    api "io.deephaven:deephaven-engine-api:$dhcVersion"
    api "io.deephaven:deephaven-engine-table:$dhcVersion"

    // File format support
    api "io.deephaven:deephaven-extensions-csv:$dhcVersion"
    api "io.deephaven:deephaven-extensions-parquet-table:$dhcVersion"

    // Utilities
    api "io.deephaven:deephaven-Configuration:$dhcVersion"
    implementation "io.deephaven:deephaven-log-factory:$dhcVersion"

    // Testing
    testImplementation "io.deephaven:deephaven-engine-test-utils:$dhcVersion"
}
```

### Maven

```xml
<properties>
    <dhc.version>VAR::COREPLUS_DHC_VERSION</dhc.version>
</properties>

<dependencies>
    <dependency>
        <groupId>io.deephaven</groupId>
        <artifactId>deephaven-engine-api</artifactId>
        <version>${dhc.version}</version>
    </dependency>
    <dependency>
        <groupId>io.deephaven</groupId>
        <artifactId>deephaven-engine-table</artifactId>
        <version>${dhc.version}</version>
    </dependency>
    <dependency>
        <groupId>io.deephaven</groupId>
        <artifactId>deephaven-extensions-csv</artifactId>
        <version>${dhc.version}</version>
    </dependency>
    <dependency>
        <groupId>io.deephaven</groupId>
        <artifactId>deephaven-extensions-parquet-table</artifactId>
        <version>${dhc.version}</version>
    </dependency>
    <dependency>
        <groupId>io.deephaven</groupId>
        <artifactId>deephaven-engine-test-utils</artifactId>
        <version>${dhc.version}</version>
        <scope>test</scope>
    </dependency>
    <!-- Add other modules as needed -->
</dependencies>
```

### Common Deephaven Community modules

| Module                               | Description                                 |
| ------------------------------------ | ------------------------------------------- |
| `deephaven-engine-api`               | Core Table API interfaces.                  |
| `deephaven-engine-table`             | Table implementations and operations.       |
| `deephaven-extensions-csv`           | CSV file reading and writing.               |
| `deephaven-extensions-parquet-table` | Parquet file reading and writing.           |
| `deephaven-Configuration`            | Property and configuration utilities.       |
| `deephaven-log-factory`              | Logging infrastructure.                     |
| `deephaven-engine-test-utils`        | Test utilities and execution context setup. |

## Core+ worker projects

For code that runs inside a Core+ Enterprise worker — such as custom utilities for Persistent Queries — you need access to the Deephaven artifact repository in addition to Maven Central.

### Gradle

Add the Deephaven and Confluent Maven repositories. Set `repoUser` and `repoPassword` in your `gradle.properties` file:

```groovy
repositories {
   mavenCentral()

    maven {
        name = 'Release Artifacts'
        url = uri('https://repo.deephaven.io/maven/release')

        credentials {
            username = findProperty("repoUser") ?: ""
            password = findProperty("repoPassword") ?: ""
        }

        authentication {
            basic(BasicAuthentication)
        }
    }

   maven {
      url 'https://packages.confluent.io/maven'
      content {
         includeGroup 'io.confluent'
         includeGroup 'org.apache.kafka'
      }
   }
}
```

Add the Core+ Database module along with the Deephaven Community dependencies:

```groovy
def dhcVersion = 'VAR::COREPLUS_DHC_VERSION'
def dheVersion = 'VAR::COREPLUS_DHE_VERSION'

dependencies {
   implementation "io.deephaven:deephaven-engine-table:$dhcVersion"
   implementation "io.deephaven:deephaven-extensions-csv:$dhcVersion"
   implementation "io.deephaven:deephaven-extensions-parquet-table:$dhcVersion"
   implementation "io.deephaven:deephaven-engine-test-utils:$dhcVersion"
   implementation "io.deephaven.coreplus:Database:$dhcVersion-$dheVersion"

   testImplementation 'org.mockito:mockito-core:4.5.1'
}
```

### Maven

Add the repositories to your `pom.xml`:

```xml
<repositories>
    <repository>
        <id>dh-artifactory</id>
        <url>https://repo.deephaven.io/maven/release</url>
    </repository>
    <repository>
        <id>confluent.io</id>
        <url>https://packages.confluent.io/maven</url>
    </repository>
</repositories>
```

Add the dependencies:

```xml
<properties>
    <dhc.version>VAR::COREPLUS_DHC_VERSION</dhc.version>
    <dhe.version>VAR::COREPLUS_DHE_VERSION</dhe.version>
</properties>

<dependencies>
    <dependency>
        <groupId>io.deephaven</groupId>
        <artifactId>deephaven-engine-table</artifactId>
        <version>${dhc.version}</version>
    </dependency>
    <dependency>
        <groupId>io.deephaven</groupId>
        <artifactId>deephaven-extensions-csv</artifactId>
        <version>${dhc.version}</version>
    </dependency>
    <dependency>
        <groupId>io.deephaven</groupId>
        <artifactId>deephaven-extensions-parquet-table</artifactId>
        <version>${dhc.version}</version>
    </dependency>
    <dependency>
        <groupId>io.deephaven</groupId>
        <artifactId>deephaven-engine-test-utils</artifactId>
        <version>${dhc.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.deephaven.coreplus</groupId>
        <artifactId>Database</artifactId>
        <version>${dhc.version}-${dhe.version}</version>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>4.5.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.10.0</version>
        <scope>test</scope>
    </dependency>
    <!-- Add other modules as needed -->
</dependencies>
```

Configure Maven credentials in your `~/.m2/settings.xml`:

```xml
<servers>
    <server>
        <id>dh-artifactory</id>
        <username>your-username</username>
        <password>your-password</password>
    </server>
</servers>
```

### JVM arguments

Deephaven logs JVM internal stats that require the following JVM argument: `--add-exports=java.management/sun.management=ALL-UNNAMED`

**Gradle:**

```groovy
test {
   jvmArgs '--add-exports=java.management/sun.management=ALL-UNNAMED'
   useJUnitPlatform()
}
```

**Maven:**

```xml
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <argLine>--add-exports=java.management/sun.management=ALL-UNNAMED</argLine>
    </configuration>
</plugin>
```

### Refresh the project

After configuring dependencies, refresh the project to download the specified modules.

![The **Load Gradle Changes** refresh button highlighted in IDEA](../../assets/IJ2.png)

## Local unit testing

The execution context setup described below works for both Deephaven Community and Core+ projects. The example that follows uses a mocked Core+ `Database`, but you can adapt the pattern for standalone Deephaven Community projects by loading test data directly with `CsvTools` or `ParquetTools`.

It may be helpful to have some local test data you can use to test your query's correctness.

The following simple query calculates the average and mid prices of stocks for a given day:

```groovy
import io.deephaven.enterprise.database.Database

db = (Database) db

date = today()

AvgStockPrices = QueryUtils.getAvgStockPriceTable(db, date)
MidStockPrices = QueryUtils.getMidStockPriceTable(db, date)
```

It uses helper methods written in Java for unit testing:

```java
import io.deephaven.engine.table.Table;
import io.deephaven.enterprise.database.Database;

public class QueryUtils {

   public static Table getAvgStockPriceTable(final Database db, final String date) {
      return db.historicalTable("LearnDeephaven", "StockTrades")
              .where("Date = `" + date + "`")
              .view("USym", "Last")
              .avgBy("USym");
   }

    public static Table getMidStockPriceTable(final Database db, final String date) {
        return db.historicalTable("LearnDeephaven", "StockQuotes")
                .where("Date = `" + date + "`")
                .lastBy("USym")
                .updateView("Mid = (Bid + Ask) / 2");
    }
}
```

We need some test data. The file `src/test/resources/StockTrades.csv` contains ten rows from the `LearnDeephaven.StockTrades` dataset, and `src/test/resources/StockQuotes.parquet` contains ten rows from `LearnDeephaven.StockQuotes`.

> [!NOTE]
> The CSV file contains AAPL and GOOG data, while the Parquet file contains additional symbols including PFE. Both files use the same date (`2017-08-25`) for filtering.

```text
Date,Timestamp,SecurityType,Exchange,USym,Sym,Last,Size,Source,ExchangeId,ExchangeTimestamp,SaleCondition
2017-08-25,2017-08-25T13:19:17.419592579-04:00,Stock,Arca,AAPL,AAPL,159.37,15,Normal,1045,2017-08-25T13:19:17.419592579-04:00,@FTI
2017-08-25,2017-08-25T13:19:17.419592579-04:00,Stock,Arca,AAPL,AAPL,159.48,85,Normal,1046,2017-08-25T13:19:17.419592579-04:00,@FTI
2017-08-25,2017-08-25T13:19:17.419592579-04:00,Stock,Arca,AAPL,AAPL,159.48,75,Normal,1047,2017-08-25T13:19:17.419592579-04:00,@TI
2017-08-25,2017-08-25T13:19:17.419592579-04:00,Stock,Arca,AAPL,AAPL,159.48,25,Normal,1048,2017-08-25T13:19:17.419592579-04:00,@FTI
2017-08-25,2017-08-25T13:19:17.419592579-04:00,Stock,Nasdaq,AAPL,AAPL,159.55,70,Normal,1055,2017-08-25T13:19:17.419592579-04:00,@TI
2017-08-25,2017-08-25T13:19:17.419592579-04:00,Stock,Arca,GOOG,GOOG,922.6,1,Normal,1406,2017-08-25T13:19:17.419592579-04:00,@TI
2017-08-25,2017-08-25T13:19:17.419592579-04:00,Stock,Arca,GOOG,GOOG,924.7,1,Normal,1410,2017-08-25T13:19:17.419592579-04:00,@TI
2017-08-25,2017-08-25T13:19:17.419592579-04:00,Stock,Nasdaq,GOOG,GOOG,924.7,1,Normal,1418,2017-08-25T13:19:17.419592579-04:00,@TI
2017-08-25,2017-08-25T13:19:17.419592579-04:00,Stock,Nasdaq,GOOG,GOOG,922.9,11,Normal,1420,2017-08-25T13:19:17.419592579-04:00,@FTI
2017-08-25,2017-08-25T13:19:17.419592579-04:00,Stock,Nasdaq,GOOG,GOOG,922.9,8,Normal,1421,2017-08-25T13:19:17.419592579-04:00,@FTI
```

The following snippets are part of a complete test class shown at the end of this section.

1. The first step is to open an [`ExecutionContext`](/core/docs/conceptual/execution-context/) so that we can use table operations like [`where`](/core/docs/reference/table-operations/filter/where) and [`updateView`](/core/docs/reference/table-operations/select/update-view). It is best practice to close the `ExecutionContext` after you are done with it. The `@BeforeAll` and `@AfterAll` tags are used so that we only need to do this once for all tests.

```java
@BeforeAll
public static void setup() {
   /*
    * Initialize the execution context for unit tests.
    * Table operations must be run within an open execution context.
    */
   final ExecutionContext executionContext = TestExecutionContext.createForUnitTests();
   final ControlledUpdateGraph updateGraph = (ControlledUpdateGraph) executionContext.getUpdateGraph();
   updateGraph.enableUnitTestMode();
   updateGraph.resetForUnitTests(false);
   executionContextCloseable = executionContext.open();

   db = getTestDatabase();
}

@AfterAll
public static void cleanUp() {
   /*
    * Clean up the execution resources.
    */
   executionContextCloseable.close();
}
```

2. Mocking the `Database` to read test data in the form of CSVs or Parquet files is easier than creating a real Database instance. This example uses Mockito:

```java
/**
 * Mocking the database allows us to test our queries' correctness
 * without the complication of creating a real database instance.
 */
private static Database getTestDatabase() {
    final Database db = mock(Database.class);
    addData(db);
    return db;
}

/**
 * The queries we are testing use historical table data. This method sets up the mock database to return
 * the test CSV and Parquet data when db.historicalTable is called.
 */
private static void addData(final Database db) {
    try {
        final Table t = CsvTools.readCsv("src/test/resources/StockTrades.csv");
        when(db.historicalTable("LearnDeephaven", "StockTrades")).thenReturn(t);
    } catch (CsvReaderException e) {
        throw new RuntimeException("Could not read StockTrades.csv test data", e);
    }

    final Table t = ParquetTools.readTable("src/test/resources/StockQuotes.parquet");
    when(db.historicalTable("LearnDeephaven", "StockQuotes")).thenReturn(t);
}
```

3. Use the methods described in the Core [Extract table values guide](/core/docs/how-to-guides/extract-table-value/) document to test your queries:

```java
@Test
public void testAvgPriceQuery() {
    final Table testResult = QueryUtils.getAvgStockPriceTable(db, TEST_DATE);

    Assertions.assertFalse(testResult.isEmpty());

    final double sumAAPL = getFirstDoubleFromColumn(testResult.where("USym = `AAPL`"), "Last");
    Assertions.assertEquals(159.472, sumAAPL, 0.0002);

    final double sumGOOG = getFirstDoubleFromColumn(testResult.where("USym = `GOOG`"), "Last");
    Assertions.assertEquals(923.56, sumGOOG, 0.0002);
}

@Test
public void testMidPriceQuery() {
    final Table testResult = QueryUtils.getMidStockPriceTable(db, TEST_DATE);

    Assertions.assertFalse(testResult.isEmpty());

    final double midPFE = getFirstDoubleFromColumn(testResult.where("USym = `PFE`"), "Mid");
    Assertions.assertEquals(33.285, midPFE, 0.0);
}

private static double getFirstDoubleFromColumn(final Table table, final String column) {
    // To extract data from a specific cell in a Table,
    // we first need the row key for that row position.
    // Row 0 does not necessarily have row key 0.
    final long rowKey = table.getRowSet().get(0);
    // Use the ColumnSource to get the value of the column for that row key
    return table.getColumnSource(column).getDouble(rowKey);
}
```

<details>
<summary>The full test class:</summary>

```java
package org.example;

import io.deephaven.csv.CsvTools;
import io.deephaven.parquet.table.ParquetTools;
import io.deephaven.csv.util.CsvReaderException;
import io.deephaven.engine.context.ExecutionContext;
import io.deephaven.engine.context.TestExecutionContext;
import io.deephaven.engine.table.Table;
import io.deephaven.engine.testutil.ControlledUpdateGraph;
import io.deephaven.enterprise.database.Database;
import io.deephaven.util.SafeCloseable;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class UnitTest {

    private static final String TEST_DATE = "2017-08-25";
    private static Database db;
    private static SafeCloseable executionContextCloseable;

    @BeforeAll
    public static void setup() {
        /*
         * Initialize the execution context for unit tests.
         * Table operations must be run within an open execution context.
         */
        final ExecutionContext executionContext = TestExecutionContext.createForUnitTests();
        final ControlledUpdateGraph updateGraph = (ControlledUpdateGraph) executionContext.getUpdateGraph();
        updateGraph.enableUnitTestMode();
        updateGraph.resetForUnitTests(false);
        executionContextCloseable = executionContext.open();

        db = getTestDatabase();
    }

    @AfterAll
    public static void cleanUp() {
        /*
         * Clean up the execution resources.
         */
        executionContextCloseable.close();
    }

    /**
     * Mocking the database allows us to test our queries' correctness
     * without the complication of creating a real database instance.
     */
    private static Database getTestDatabase() {
        final Database db = mock(Database.class);
        addData(db);
        return db;
    }

    /**
     * The queries we are testing use historical table data. This method sets up the mock database to return
     * the test CSV and Parquet data when db.historicalTable is called.
     */
    private static void addData(final Database db) {
        try {
            final Table t = CsvTools.readCsv("src/test/resources/StockTrades.csv");
            when(db.historicalTable("LearnDeephaven", "StockTrades")).thenReturn(t);
        } catch (CsvReaderException e) {
            throw new RuntimeException("Could not read StockTrades.csv test data", e);
        }

        final Table t = ParquetTools.readTable("src/test/resources/StockQuotes.parquet");
        when(db.historicalTable("LearnDeephaven", "StockQuotes")).thenReturn(t);
    }

    @Test
    public void testAvgPriceQuery() {
        final Table testResult = QueryUtils.getAvgStockPriceTable(db, TEST_DATE);

        Assertions.assertFalse(testResult.isEmpty());

        final double sumAAPL = getFirstDoubleFromColumn(testResult.where("USym = `AAPL`"), "Last");
        Assertions.assertEquals(159.472, sumAAPL, 0.0002);

        final double sumGOOG = getFirstDoubleFromColumn(testResult.where("USym = `GOOG`"), "Last");
        Assertions.assertEquals(923.56, sumGOOG, 0.0002);
    }

    @Test
    public void testMidPriceQuery() {
        final Table testResult = QueryUtils.getMidStockPriceTable(db, TEST_DATE);

        Assertions.assertFalse(testResult.isEmpty());

        final double midPFE = getFirstDoubleFromColumn(testResult.where("USym = `PFE`"), "Mid");
        Assertions.assertEquals(33.285, midPFE, 0.0);
    }

    private static double getFirstDoubleFromColumn(final Table table, final String column) {
        // To extract data from a specific cell in a Table,
        // we first need the row key for that row position.
        // Row 0 does not necessarily have row key 0.
        final long rowKey = table.getRowSet().get(0);
        // Use the ColumnSource to get the value of the column for that row key
        return table.getColumnSource(column).getDouble(rowKey);
    }
}
```

</details>

## Connect to a remote DB

The steps above cover testing query logic locally, without a running Deephaven server. Client applications can also connect to Deephaven server installations to run queries on a remote database. See the [Core+ Java Client](../../clients/java/coreplus-java-client.md) for more information.

## Related documentation

- [Core+ Java Client](../../clients/java/coreplus-java-client.md) — connect to Deephaven server installations to run queries on a remote database
- [Execution context](/core/docs/conceptual/execution-context/)
- [Extract table values](/core/docs/how-to-guides/extract-table-value/)
- [`Database` interface](https://docs.deephaven.io/javadoc/coreplus/2026.01/io/deephaven/enterprise/database/Database.html)
