# How to Use the OpenMetadata SDK for Java: A Complete Guide

> Master the OpenMetadata SDK for Java with this guide. Learn to configure the client, manage metadata entities, and create tables efficiently using simple API calls.

- Repository: [OpenMetadata/OpenMetadata](https://github.com/open-metadata/OpenMetadata)
- Tags: how-to-guide
- Published: 2026-04-23

---

**Use the OpenMetadata Java SDK by configuring `OpenMetadataConfig` with your server URL and token, instantiating `OpenMetadataClient`, setting it as the default for fluent helpers, then calling methods like `Tables.create()` or `Tables.find()` to manage metadata entities.**

The OpenMetadata SDK provides a type-safe, fluent Java API that mirrors the OpenMetadata REST API. This guide walks through the complete workflow—from configuration to CRUD operations, CSV import/export, and working with multiple entity types—based on the actual source code in the `open-metadata/OpenMetadata` repository.

---

## Setting Up the OpenMetadata SDK

### Add the Maven Dependency

Include the SDK in your [`pom.xml`](https://github.com/open-metadata/OpenMetadata/blob/main/pom.xml):

```xml
<dependency>
    <groupId>org.openmetadata</groupId>
    <artifactId>openmetadata-sdk</artifactId>
    <version>1.5.0</version>
</dependency>

```

The latest version is defined in the SDK's [`pom.xml`](https://github.com/open-metadata/OpenMetadata/blob/main/pom.xml) at [`openmetadata-sdk/pom.xml`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/pom.xml).

---

## Configuring the OpenMetadata Client

### Create the Configuration

The `OpenMetadataConfig` class in [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/config/OpenMetadataConfig.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/config/OpenMetadataConfig.java) provides a builder for connection settings:

```java
import org.openmetadata.sdk.config.OpenMetadataConfig;

OpenMetadataConfig config = OpenMetadataConfig.builder()
        .serverUrl("http://localhost:8585/api")
        .accessToken("YOUR_PERSONAL_ACCESS_TOKEN")
        .debug(true)
        .build();

```

Generate your personal access token in the OpenMetadata UI under **Settings > Tokens**.

### Initialize the Client

The `OpenMetadataClient` class in [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/client/OpenMetadataClient.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/client/OpenMetadataClient.java) aggregates service objects for each entity type:

```java
import org.openmetadata.sdk.client.OpenMetadataClient;

OpenMetadataClient client = new OpenMetadataClient(config);

```

### Register the Default Client

Fluent helpers require a default client. The `Tables` class in [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java) provides the registration mechanism:

```java
import static org.openmetadata.sdk.fluent.Tables.*;

Tables.setDefaultClient(client);

```

Once set, all fluent classes (`Tables`, `Databases`, `Teams`, `Users`, etc.) automatically retrieve the client via `Tables.getClient()`.

---

## Core Fluent Operations with the OpenMetadata SDK

### Create a Table

The `Tables.create()` method returns a `TableCreator` that builds and executes the REST call:

```java
import org.openmetadata.schema.api.data.CreateTable;
import org.openmetadata.schema.type.Column;
import org.openmetadata.schema.type.ColumnDataType;

// Build the request object
CreateTable request = new CreateTable()
        .name("customers")
        .databaseSchema("sample_data.ecommerce_db.shopify")
        .description("Customer information")
        .columns(List.of(
                new Column()
                        .name("id")
                        .dataType(ColumnDataType.BIGINT),
                new Column()
                        .name("email")
                        .dataType(ColumnDataType.VARCHAR)
                        .dataLength(255),
                new Column()
                        .name("created_at")
                        .dataType(ColumnDataType.TIMESTAMP)));

// Execute via fluent API
var table = Tables.create()
        .withDescription(request.getDescription())
        .inSchema(request.getDatabaseSchema())
        .withColumns(request.getColumns())
        .name(request.getName())
        .execute();  // Returns org.openmetadata.schema.entity.data.Table

```

The `TableCreator` forwards the request to `client.tables().create(request)` as implemented in [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java) lines 69-76.

### Retrieve a Table

Fetch by UUID or fully-qualified name with optional field expansion:

```java
// By UUID
var table = Tables.get("3fa85f64-5717-4562-b3fc-2c963f66afa6");

// By FQN with related data
var table = Tables.findByName("sample_data.ecommerce_db.shopify.customers")
        .includeOwners()
        .includeTags()
        .fetch()
        .get();

```

The `find` and `findByName` helpers construct proper query parameters (`include`, `fields`) as shown in [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java) lines 78-92.

### Update a Table

Modify fields and persist changes:

```java
var updated = Tables.find(table.getId().toString())
        .fetch()
        .withDescription("Updated description")
        .withDisplayName("Customers")
        .save();  // PATCHes the entity and returns refreshed Table

```

`FluentTable.save()` detects modifications and calls `client.tables().update(id, entity)` per [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java) lines 99-104.

### Delete a Table

Remove with optional cascade and permanence:

```java
Tables.find(table.getId().toString())
        .delete()
        .recursively()   // cascade delete
        .permanently()   // hard delete (vs. soft delete)
        .confirm();

```

`TableDeleter` builds query parameters (`recursive`, `hardDelete`) and invokes `client.tables().delete(id, params)` as implemented in [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java) lines 67-75.

### List Tables

Paginate through results:

```java
List<Tables.FluentTable> tables = Tables.list()
        .limit(20)
        .after("cursor-token")   // pagination cursor
        .fetch();               // → List<FluentTable>

```

The lister wraps the generic `list` endpoint and converts each `Table` to `FluentTable` per [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java) lines 94-102.

---

## CSV Import and Export with the OpenMetadata SDK

### Export Table Definition to CSV

```java
String csv = Tables.exportCsv("sample_data.ecommerce_db.shopify.customers")
        .async()   // optional – returns job ID for async processing
        .toCsv();  // → CSV string (or job ID if async)

```

`CsvExporter` calls `client.tables().exportCsv(...)` or `exportCsvAsync(...)` as shown in [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java) lines 15-22.

### Import CSV to Update Columns

```java
String csvData = """
        columnName,dataType,dataLength,description
        phone_number,VARCHAR,20,Customer phone
        """;

String result = Tables.importCsv("sample_data.ecommerce_db.shopify.customers")
        .withData(csvData)
        .dryRun()   // validates only; omit for actual import
        .apply();   // → response JSON (or job ID for async)

```

`CsvImporter` reads CSV from string or file, then invokes `client.tables().importCsv(...)` or the async variant per [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java) lines 44-52.

---

## Working with Other Entities in the OpenMetadata SDK

The SDK provides parallel fluent helpers for all major entity types:

| Entity | Fluent Helper | Example |
|--------|---------------|---------|
| Database | `Databases` | `Databases.create().name("sales").in("sample_data").execute();` |
| Team | `Teams` | `Teams.create().name("analytics").withDescription("Analytics team").execute();` |
| User | `Users` | `Users.create().name("john.doe").withEmail("john.doe@example.com").execute();` |
| Dashboard | `Dashboards` | `Dashboards.findByName("sales_metrics").fetch();` |
| Pipeline | `Pipelines` | `Pipelines.list().limit(50).fetch();` |

All helpers follow the same pattern: `setDefaultClient()`, then use `create()`, `find()`, `list()`, or direct service calls (`client.users()`, `client.databases()`, …).

---

## Complete Minimal Example

```java
import org.openmetadata.sdk.config.OpenMetadataConfig;
import org.openmetadata.sdk.client.OpenMetadataClient;
import static org.openmetadata.sdk.fluent.Tables.*;

public class SdkDemo {
    public static void main(String[] args) {
        // 1️⃣ Config & client
        var cfg = OpenMetadataConfig.builder()
                .serverUrl("http://localhost:8585/api")
                .accessToken(System.getenv("OM_TOKEN"))
                .debug(true)
                .build();

        var client = new OpenMetadataClient(cfg);
        Tables.setDefaultClient(client);

        // 2️⃣ Create a table
        var table = Tables.create()
                .name("orders")
                .inSchema("sample_data.sales_db.public")
                .withDescription("Orders table")
                .withColumns(List.of(
                        new org.openmetadata.schema.type.Column()
                                .name("order_id")
                                .dataType(org.openmetadata.schema.type.ColumnDataType.BIGINT),
                        new org.openmetadata.schema.type.Column()
                                .name("amount")
                                .dataType(org.openmetadata.schema.type.ColumnDataType.DOUBLE)))
                .execute();

        System.out.println("Created: " + table.getFullyQualifiedName());

        // 3️⃣ Update description
        Tables.find(table.getId().toString())
                .fetch()
                .withDescription("Updated orders description")
                .save();

        // 4️⃣ Export to CSV
        String csv = Tables.exportCsv(table.getFullyQualifiedName()).toCsv();
        System.out.println("CSV:\n" + csv);
    }
}

```

This demonstrates the complete lifecycle: **configure → client → default client → fluent operations**. Run after adding the SDK dependency and providing a valid token.

---

## Key Source Files in the OpenMetadata SDK

| File | Purpose | Location |
|------|---------|----------|
| [`OpenMetadataConfig.java`](https://github.com/open-metadata/OpenMetadata/blob/main/OpenMetadataConfig.java) | Builder for connection settings (URL, token, timeouts) | [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/config/OpenMetadataConfig.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/config/OpenMetadataConfig.java) |
| [`OpenMetadataClient.java`](https://github.com/open-metadata/OpenMetadata/blob/main/OpenMetadataClient.java) | Core client creating service objects and handling HTTP transport | [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/client/OpenMetadataClient.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/client/OpenMetadataClient.java) |
| [`Tables.java`](https://github.com/open-metadata/OpenMetadata/blob/main/Tables.java) | Fluent wrapper for all table operations (create, find, list, CSV, etc.) | [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java) |
| [`PureFluentAPIExample.java`](https://github.com/open-metadata/OpenMetadata/blob/main/PureFluentAPIExample.java) | End-to-end sample demonstrating client initialization, CRUD, and CSV usage | [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/examples/PureFluentAPIExample.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/examples/PureFluentAPIExample.java) |
| [`TableService.java`](https://github.com/open-metadata/OpenMetadata/blob/main/TableService.java) | Low-level service communicating with the `/v1/tables` REST endpoint | [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/services/dataassets/TableService.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/services/dataassets/TableService.java) |

These files illustrate the SDK architecture: **configuration → client → service objects → fluent helpers**.

---

## Summary

- **Configure** with `OpenMetadataConfig.builder()` to set server URL, access token, and optional debug mode.
- **Instantiate** `OpenMetadataClient` with your configuration to create the HTTP transport layer.
- **Register** the client as default via `Tables.setDefaultClient()` to enable fluent helpers across all entity types.
- **Operate** using fluent methods—`create()`, `find()`, `list()`, `save()`, `delete()`—with built-in pagination, field expansion, and CSV support.
- **Extend** the same pattern to `Databases`, `Teams`, `Users`, `Dashboards`, `Pipelines`, and other entities.

The OpenMetadata SDK abstracts REST complexity while preserving full API coverage, enabling compile-time type safety and idiomatic Java patterns for data catalog operations.

---

## Frequently Asked Questions

### How do I authenticate with the OpenMetadata SDK?

Generate a personal access token in the OpenMetadata UI under **Settings > Tokens**, then pass it to `OpenMetadataConfig.builder().accessToken("your-token")`. The SDK sends this as a Bearer token in the `Authorization` header for all requests.

### What is the difference between the fluent API and direct service calls?

The **fluent API** (`Tables.create()`, `Tables.find()`) provides a chainable, type-safe interface that handles parameter building and object conversion. **Direct service calls** (`client.tables().create(request)`) offer lower-level access to the REST endpoints. Both use the same underlying `TableService` in [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/services/dataassets/TableService.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/services/dataassets/TableService.java).

### How do I handle pagination when listing entities?

Use the `.after("cursor")` and `.limit(n)` methods on list operations. The `Tables.list()` method in [`openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java`](https://github.com/open-metadata/OpenMetadata/blob/main/openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java) converts the paginated response into a `List<FluentTable>` while preserving the cursor for subsequent requests.

### Can I perform bulk operations with the OpenMetadata SDK?

Yes. Use `importCsv()` and `exportCsv()` methods for bulk column updates and table schema exports. Add `.async()` to run these as background jobs, returning a job ID you can poll for completion status.