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

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:

<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 at 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 provides a builder for connection settings:

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 aggregates service objects for each entity type:

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 provides the registration mechanism:

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:

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 lines 69-76.

Retrieve a Table

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

// 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 lines 78-92.

Update a Table

Modify fields and persist changes:

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 lines 99-104.

Delete a Table

Remove with optional cascade and permanence:

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 lines 67-75.

List Tables

Paginate through results:

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 lines 94-102.


CSV Import and Export with the OpenMetadata SDK

Export Table Definition to CSV

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 lines 15-22.

Import CSV to Update Columns

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 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

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 Builder for connection settings (URL, token, timeouts) openmetadata-sdk/src/main/java/org/openmetadata/sdk/config/OpenMetadataConfig.java
OpenMetadataClient.java Core client creating service objects and handling HTTP transport openmetadata-sdk/src/main/java/org/openmetadata/sdk/client/OpenMetadataClient.java
Tables.java Fluent wrapper for all table operations (create, find, list, CSV, etc.) openmetadata-sdk/src/main/java/org/openmetadata/sdk/fluent/Tables.java
PureFluentAPIExample.java End-to-end sample demonstrating client initialization, CRUD, and CSV usage openmetadata-sdk/src/main/java/org/openmetadata/sdk/examples/PureFluentAPIExample.java
TableService.java Low-level service communicating with the /v1/tables REST endpoint 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.

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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →