OpenMetadata Coding Standards: Complete Guide to Java, TypeScript, and Python Guidelines
OpenMetadata enforces strict, cross-language coding standards documented in CLAUDE.md and enforced automatically via CI pipelines to ensure production-ready, maintainable code.
The OpenMetadata project maintains a unified codebase spanning Java backend services, TypeScript/React front-end applications, and Python ingestion connectors. This guide breaks down the project's coding standards as defined in CLAUDE.md and DEVELOPER.md, with practical examples from the source code.
General Coding Principles
All contributors must follow these foundational rules across every language:
- No unnecessary comments — write self-documenting code with clear naming
- Every change must pass CI lint and format checks before merge
- Follow language-specific standards detailed in the sections below
These rules appear in CLAUDE.md – Comments Policy and are enforced in .github/workflows/** pipelines.
Java Coding Standards
The OpenMetadata backend in openmetadata-service/src/main/java/** follows strict Java 21 conventions defined in CLAUDE.md – Java Code Requirements.
Formatting and CI Enforcement
Run mvn spotless:apply after every Java change. The CI pipeline fails if code is unformatted.
Method Structure Rules
| Metric | Limit | Rationale |
|---|---|---|
| Method length | ≤ 15 lines | Single responsibility |
| Nesting levels | ≤ 3 | Readable control flow |
| Cyclomatic complexity | ≤ 10 | Testable paths |
| Parameters | ≤ 5 | Use parameter objects |
Import and Modifiers
- No wildcard imports — import only required classes
- Use
finalfor immutable local variables - Make defensive copies for collections passed to constructors
Modern Java 21 Features
Prefer pattern matching, switch expressions, List.of(), and correct Optional usage. Avoid magic strings — use constants or enums.
Java Example: Clean Method Structure
// ✅ Good: short, single-purpose, early-return style
public void deleteEntity(UUID id) {
Entity entity = getEntity(id);
if (entity == null) {
throw new EntityNotFoundException(id);
}
if (!entity.isDeletable()) {
throw new IllegalArgumentException("Entity cannot be deleted");
}
repository.delete(entity);
}
This method from openmetadata-service demonstrates the 15-line limit, early returns, and clear naming that CLAUDE.md requires.
TypeScript and Front-End Coding Standards
The React application in openmetadata-ui/src/main/resources/ui/** follows strict TypeScript rules documented in CLAUDE.md – TypeScript/Frontend Code Requirements.
Type Safety
- Never use
any— use proper types orunknownwith type guards - The ESLint
no-unsafe-anyrule catches violations
Import Organization
Follow strict import ordering:
- External libraries
- Internal absolute imports
- Relative imports
- Assets
Run yarn organize-imports:cli before committing.
ESLint Rules
| Rule | Requirement |
|---|---|
No console.log in production |
Remove or use proper logging |
| Strict equality | === over == |
| Line length | Maximum 200 characters |
| JSX | Self-closing tags, alphabetic props |
Formatting
Run yarn prettier before every commit.
Internationalization
All UI strings must use useTranslation with keys from locale JSON files. Run yarn i18n to sync keys across all locales. Keys use kebab-case.
TypeScript Example: Proper Typing and i18n
import type { Table } from 'generated/api/v1/table';
import type { RJSFSchema } from '@rjsf/utils';
const TableCard: React.FC<{ table: Table }> = ({ table }) => {
const { t } = useTranslation();
return (
<Card title={t('label.table')}>
<pre>{JSON.stringify(table, null, 2)}</pre>
</Card>
);
};
This component from openmetadata-ui demonstrates no any, proper import ordering, and useTranslation for the 'label.table' key.
Python Ingestion Coding Standards
The ingestion framework in ingestion/src/metadata/** follows pytest-based standards in CLAUDE.md – Python Code Requirements.
Testing Framework
- Use pytest exclusively — no
unittest - Use plain
assertstatements, notself.assertEqual() - Replace
setUp/tearDownwith pytest fixtures
Test Design
- Mock external services only — prefer integration tests for real behavior
- Every bug fix must add a failing test first
Connector Organization
Keep connector-specific logic in its own directory. Never place connector code in shared helper files like builders.py.
Formatting
Run make lint and make py_format before committing. These enforce Pylint, Black, and isort rules.
Python Example: Proper Connector Placement and pytest
# ingestion/src/metadata/ingestion/source/database/postgres/connection.py
class PostgresConnection(BaseSQLConnection):
def get_service_connection(self) -> PostgresConnectionConfig:
# Connector-specific logic lives here
return self.config
def test_postgres_connection_success():
conn = PostgresConnection(config=valid_cfg)
assert conn.test_connection() is True
This follows the rule that PostgresConnection stays in postgres/ rather than leaking into shared builders.py.
UI Styling Standards
The design system in openmetadata-ui uses Tailwind with strict conventions from CLAUDE.md – Styling.
Component Library
Use openmetadata-ui-core-components — never add MUI (Material-UI) directly.
Tailwind Configuration
- Use
tw:prefix for all Tailwind classes - Reference CSS tokens from
globals.css— no hard-coded colors or spacing
Custom CSS
- Use BEM naming for custom CSS
- No
.lessfiles for new styles
Styling Example: Tailwind with Prefix
<div className="tw:flex tw:items-center tw:justify-between tw:bg-primary-500 tw:p-4">
<Button>{t('label.run')}</Button>
</div>
Using tw:flex instead of flex ensures compatibility with the project's style linting.
Testing Standards
Quality gates in .github/workflows/** enforce comprehensive testing rules from CLAUDE.md – Testing.
Coverage Requirements
- 90% line coverage on changed code
- Missing coverage blocks merge
Asynchronous Testing
- No
Thread.sleep()— use Awaitility (Java) or Playwright's web-first assertions
Playwright E2E Rules
Avoid anti-patterns:
- No
waitForLoadState('networkidle') - No
page.pause() - No
.onlyin committed tests
Regression Testing
Every bug fix must include a failing test that proves the bug, then passes with the fix.
Documentation Standards
Public APIs and UI text follow strict documentation rules in [CLAUDE.md](https://github.com/open-metadata/OpenMetadata/blob/main/CLAUDE.md).
API Documentation
All public Java and TypeScript APIs require JavaDoc or TypeScript doc comments.
Internationalization
- All UI strings via
useTranslationhook - Locale keys in kebab-case
- Sync across all locale files with
yarn i18n
Key Configuration Files
| File | Purpose |
|---|---|
[CLAUDE.md](https://github.com/open-metadata/OpenMetadata/blob/main/CLAUDE.md) |
Central coding standards for all languages |
[DEVELOPER.md](https://github.com/open-metadata/OpenMetadata/blob/main/DEVELOPER.md) |
Workflow guidance and tooling commands |
.github/workflows/** |
CI pipelines enforcing all standards |
openmetadata-service/src/main/java/** |
Java backend implementation |
openmetadata-ui/src/main/resources/ui/** |
React/TypeScript frontend |
ingestion/src/metadata/** |
Python ingestion framework |
Summary
OpenMetadata coding standards create a maintainable, production-ready codebase through:
- Automated enforcement — CI pipelines run
mvn spotless:apply,yarn prettier,make lint, and coverage gates - Strict language rules — Java 15-line methods, TypeScript
no-any, Python pytest patterns - Architectural boundaries — connector-specific logic isolated, shared components in
openmetadata-ui-core-components - Quality gates — 90% coverage, no
Thread.sleep(), every bug fix proven with a test
Contributors should bookmark [CLAUDE.md](https://github.com/open-metadata/OpenMetadata/blob/main/CLAUDE.md) as the single source of truth and run the documented formatter commands before every commit.
Frequently Asked Questions
What is the maximum allowed method length in OpenMetadata's Java code?
Methods must be 15 lines or fewer. This rule in CLAUDE.md enforces single-responsibility methods. The CI fails builds where mvn spotless:apply cannot automatically fix violations.
How do I format TypeScript code before committing?
Run yarn organize-imports:cli followed by yarn prettier. These commands enforce import ordering, eliminate any types, and apply the 200-character line limit. The CI rejects unformatted TypeScript changes.
Where should I place Python connector-specific logic?
Always in the connector's own directory under ingestion/src/metadata/ingestion/source/. Never place connector logic in shared helpers like builders.py. This boundary prevents tight coupling and ensures clean architecture.
What test coverage is required for code changes?
90% line coverage on all changed code. The CI pipeline calculates coverage and blocks merges below this threshold. Additionally, every bug fix must include a failing test that passes with the fix applied.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →