This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

How-to Guides

Goal-oriented recipes for getting specific tasks done with Jikkou.

These guides answer “how do I…?” — practical, step-by-step recipes for getting specific tasks done with Jikkou. If you are learning Jikkou for the first time, start with the Tutorials. For exhaustive option-by-option detail, see the Reference.

Install & operate

Manage resources

Govern & operate safely

1 - Install Jikkou

This guide shows how to install the Jikkou CLI.

This guide covers installing the Jikkou CLI, either from source or from releases. To install the REST server, see Install API Server.

The latest stable release of jikkou (x86) for Linux, and macOS can be retrieved via SDKMan!:

sdk install jikkou

From The Jikkou Project

Releases

Every release released versions of Jikkou is available:

These are the official ways to get Jikkou releases that you manually downloaded and installed.

Install From Release distribution

  1. Download your desired version
  2. Unpack it (unzip jikkou-<version>-linux-x86_64.zip)
  3. Move the unpacked directory to the desired destination (mv jikkou-<version>-linux-x86_64 /opt/jikkou)
  4. Add the executable to your PATH (export PATH=$PATH:/opt/jikkou/bin)

From there, you should be able to run the client: jikkou help.

It is recommended to install the bash/zsh completion script jikkou_completion:

wget https://raw.githubusercontent.com/streamthoughts/jikkou/main/jikkou_completion -O jikkou_completion

or alternatively, run the following command for generation the completion script.

$ source <(jikkou generate-completion)

Using Docker Image

# Create a Jikkou configfile (i.e., jikkouconfig)
cat << EOF >jikkouconfig
{
  "currentContext" : "localhost",
  "localhost" : {
    "configFile" : null,
    "configProps" : {
     "provider.kafka.config.client.bootstrap.servers" : "localhost:9092"
    }
  }
}
EOF

# Run Docker
docker run -it \
--net host \
--mount type=bind,source="$(pwd)"/jikkouconfig,target=/etc/jikkou/config \
streamthoughts/jikkou:latest -V

Development Builds

In addition to releases you can download or install development snapshots of Jikkou.

From Docker Hub

Docker images are built and push to Docker Hub from the latest main branch. They are not official releases, and may not be stable. However, they offer the opportunity to test the cutting edge features.

$ docker run -it streamthoughts/jikkou:main

From Source (Linux, macOS)

Building Jikkou from source is slightly more work, but is the best way to go if you want to test the latest ( pre-release) Jikkou version.

Prerequisites

To build the project you will need:

  • Java 25 (i.e. $JAVA_HOME environment variable is configured).
  • GraalVM 25.0.2 or newer to create native executable
  • TestContainer to run integration tests

Create Native Executable

# Build and run all tests
./mvnw clean verify -Pnative

You can then execute the native executable with: ./jikkou-cli/target/jikkou-$PROJECT_VERSION-runner

Build Debian Package (.deb)

# Build and run all tests
./mvnw clean package -Pnative
./mvnw package -Pdeb

You can then install the package with: sudo dpkg -i ./dist/jikkou-$PROJECT_VERSION-linux-x86_64.deb

NOTE: Jikkou will install itself in the directory : /opt/jikkou

Build RPM Package

# Build and run all tests
./mvnw clean package -Pnative
./mvnw package -Prpm

The RPM package will available in the ./target/rpm/jikkou/RPMS/noarch/ directory.

1.1 - Install Jikkou API Server

This guide shows how to install the Jikkou API Server.

Releases

The latest stable release of Jikkou API Server is available:

Standalone Installation

Follow these few steps to download the latest stable versions and get started.

Prerequisites

To be able to run Jikkou API Server, the only requirement is to have a working Java 25 installation. You can check the correct installation of Java by issuing the following command:

java -version

Step 1: Download

Download the latest Java binary distribution from the GitHub Releases (e.g. jikkou-api-server-$LATEST_VERSION.zip)

Unpack the download distribution and move the unpacked directory to a desired destination

unzip jikkou-api-server-$LATEST_VERSION.zip
mv jikkou-api-server-$LATEST_VERSION /opt/jikkou

Step 2: Start the API Server

Launch the application with:

./bin/jikkou-api-server.sh

Step 3: Test the API Server

$ curl -sX GET http://localhost:28082 -H "Accept: application/json" | jq

{
  "version": "0.37.0",
  "build_time": "2025-08-26T00:00:00+0000",
  "commit_id": "dae1be11c092256f36c18c8f1d90f16b0c951716",
  "_links": {
    "self": {
      "href": "/",
      "templated": false
    },
    "get-apis": {
      "href": "/apis",
      "templated": false
    }
  }
}

Step 4: Stop the API Server

PID=`ps -ef | grep -v grep | grep JikkouApiServer | awk '{print $2}'`
kill $PID

Docker

# Run Docker
docker run -it \
--net host \
streamthoughts/jikkou-api-server:latest

Development Builds

In addition to releases you can download or install development snapshots of Jikkou API Server.

From Docker Hub

Docker images are built and push to Docker Hub from the latest main branch.

They are not official releases, and may not be stable. However, they offer the opportunity to test the cutting edge features.

$ docker run -it streamthoughts/jikkou-api-server:main

Next Steps

2 - Automating

Integrate Jikkou into CI/CD pipelines.

2.1 - Automate Jikkou with GitHub Actions

Learn Jikkou Setup Github Action in your CI/CD Workflows

Setup Jikkou

The streamthoughts/setup-jikkou action is a JavaScript action that sets up Jikkou in your GitHub Actions workflow by:

  • Downloading a specific version of Jikkou CLI and adding it to the PATH.
  • Configuring JIKKOU CLI with a custom configuration file.

After you’ve used the action, subsequent steps in the same job can run arbitrary Jikkou commands using the GitHub Actions run syntax. This allows most Jikkou commands to work exactly like they do on your local command line.

Usage

steps:
  - uses: streamthoughts/setup-jikkou@v1

A specific version of Jikkou CLI can be installed:

steps:
  - uses: streamthoughts/setup-jikkou@v0.1.0
    with:
      jikkou_version: 0.37.0

A custom configuration file can be specified:

steps:
  - uses: streamthoughts/setup-jikkou@v0.1.0
    with:
      jikkou_config: ./config/jikkouconfig.json

Inputs

This Action additionally supports the following inputs :

PropertyDefaultDescription
jikkou_versionlatestThe version of Jikkou CLI to install. A value of latest will install the latest version of Jikkou CLI.
jikkou_configThe path to the Jikkou CLI config file. If set, Jikkou CLI will be configured through the JIKKOUCONFIG environment variable.

See also

2.2 - Detect Configuration Drift

Run jikkou diff on a schedule to detect when your clusters no longer match what is in Git.

Configuration drift happens to every Kafka platform: someone bumps retention.ms during an incident with a vendor UI, a topic gets created by hand, an ACL is “temporarily” widened. Because Jikkou is stateless and always compares your Git-versioned definitions against the actual cluster state, detecting drift is a single command:

jikkou diff --files ./resources --fail-on-changes

Exit codes

With --fail-on-changes, jikkou diff uses distinct exit codes so CI can react precisely:

CodeMeaning
0No changes: cluster matches Git
1Validation or execution error
2Usage error (invalid flags or arguments)
3Drift detected: at least one pending change

A one-line summary is printed to stderr (for example, 3 changes detected: 1 CREATE, 2 UPDATE), while stdout carries the full machine-readable diff (YAML by default, -o JSON available).

Scheduled drift check with GitHub Actions

The workflow below runs every hour using the streamthoughts/setup-jikkou action, uploads the diff as an artifact, and opens an issue when drift is detected:

name: Kafka Drift Detection

on:
  schedule:
    - cron: '0 * * * *'   # every hour
  workflow_dispatch: {}

jobs:
  drift:
    runs-on: ubuntu-latest
    permissions:
      issues: write
    steps:
      - uses: actions/checkout@v4

      - uses: streamthoughts/setup-jikkou@v1
        with:
          jikkou_config: ${{ github.workspace }}/.jikkou/config

      - name: Check for drift
        id: diff
        run: |
          set +e
          jikkou diff --files ./resources --fail-on-changes -o YAML > drift.yaml
          echo "exit_code=$?" >> "$GITHUB_OUTPUT"          

      - name: Upload diff
        if: steps.diff.outputs.exit_code == '3'
        uses: actions/upload-artifact@v4
        with:
          name: drift-report
          path: drift.yaml

      - name: Open an issue on drift
        if: steps.diff.outputs.exit_code == '3'
        run: |
          gh issue create \
            --title "Kafka configuration drift detected ($(date -u +%F))" \
            --body "jikkou diff found pending changes. Download the drift-report artifact from run ${{ github.run_id }}."          
        env:
          GH_TOKEN: ${{ github.token }}

      - name: Fail on error
        if: steps.diff.outputs.exit_code == '1' || steps.diff.outputs.exit_code == '2'
        run: exit 1

Instead of opening an issue, the same gate (exit_code == '3') can post to Slack, page an on-call rotation, or even trigger a jikkou apply job to revert the drift automatically.

Running without cluster credentials

CI runners do not need direct access to your Kafka clusters. Run the Jikkou API server inside your platform, and point the CLI at it with proxy mode:

jikkou {
  proxy {
    enabled = true
    url = "https://jikkou.my-platform.internal"
    security {
      access-token = ${?JIKKOU_API_TOKEN}
    }
  }
}

With this configuration, the workflow above only needs an API token: cluster credentials stay on the server side.

3 - Manage Kafka ACLs

Declare and apply Access Control Lists (ACLs) for principals on your Apache Kafka cluster.

This guide shows how to manage Kafka Access Control Lists (ACLs) as code with Jikkou. For the full resource specification, see the Kafka Authorizations reference.

Before you begin

  • A running Apache Kafka cluster with an authorizer enabled (e.g. StandardAuthorizer or AclAuthorizer).
  • A configured Jikkou context pointing at your cluster — see Getting Started.
  • A principal with permission to manage ACLs.

1. Describe the ACLs you want

Create a file describing the desired authorizations for each principal.

file: kafka-acls.yaml

---
apiVersion: "kafka.jikkou.io/v1beta2"
kind: "KafkaPrincipalAuthorization"
metadata:
  name: "User:Alice"
spec:
  acls:
    - resource:
        type: 'topic'
        pattern: 'orders-'
        patternType: 'PREFIXED'
      type: "ALLOW"
      operations: [ 'READ', 'WRITE' ]
      host: "*"

2. Preview the changes

Always run in --dry-run first to review what Jikkou will do:

jikkou apply --files ./kafka-acls.yaml --dry-run

3. Apply the ACLs

jikkou apply --files ./kafka-acls.yaml

Reuse permissions with roles

To avoid repeating the same ACLs for many principals, define a KafkaPrincipalRole once and reference it from several principals:

---
apiVersion: "kafka.jikkou.io/v1beta2"
kind: "KafkaPrincipalRole"
metadata:
  name: "OrdersReadWrite"
spec:
  acls:
    - type: "ALLOW"
      operations: [ 'READ', 'WRITE' ]
      resource:
        type: 'topic'
        pattern: 'orders-'
        patternType: 'PREFIXED'
      host: "*"
---
apiVersion: "kafka.jikkou.io/v1beta2"
kind: "KafkaPrincipalAuthorization"
metadata:
  name: "User:Alice"
spec:
  roles:
    - "OrdersReadWrite"

Delete ACLs

Jikkou reconciles to the declared state. With apply, any ACL that exists on the cluster but is not present in your resource files will be deleted for the principals you describe. To delete all ACLs for a principal, add the delete annotation:

apiVersion: "kafka.jikkou.io/v1beta2"
kind: "KafkaPrincipalAuthorization"
metadata:
  name: "User:Alice"
  annotations:
    jikkou.io/delete: true
spec:
  acls: []

4 - Manage Schema Registry Subjects

Register and evolve Avro, Protobuf, and JSON schemas in your Schema Registry as code.

This guide shows how to manage Schema Registry subjects with Jikkou. For the full resource specification, see the Schema Registry Subjects reference.

Before you begin

1. Describe a subject

Keep your schema in its own file and reference it from the resource with $ref.

file: subject-user.yaml

---
apiVersion: "schemaregistry.jikkou.io/v1beta2"
kind: "SchemaRegistrySubject"
metadata:
  name: "User"
  annotations:
    schemaregistry.jikkou.io/normalize-schema: true
spec:
  compatibilityLevel: "FULL_TRANSITIVE"
  schemaType: "AVRO"
  schema:
    $ref: ./user-schema.avsc

file: user-schema.avsc

{
  "namespace": "example.avro",
  "type": "record",
  "name": "User",
  "fields": [
    { "name": "name", "type": ["null", "string"], "default": null },
    { "name": "favorite_number", "type": ["null", "int"], "default": null }
  ]
}

2. Preview and apply

jikkou apply --files ./subject-user.yaml --dry-run   # review
jikkou apply --files ./subject-user.yaml             # apply

3. Evolve the schema safely

To evolve a schema, edit the .avsc file and re-apply. Jikkou registers a new version only when the schema actually changes, and the registry rejects changes that violate the subject’s compatibilityLevel. Run with --dry-run first to confirm the diff is what you expect.

Manage many subjects at once

Use a SchemaRegistrySubjectList (handy with templating) to manage multiple subjects in a single file:

apiVersion: "schemaregistry.jikkou.io/v1beta2"
kind: "SchemaRegistrySubjectList"
items: []   # an array of SchemaRegistrySubject

5 - Manage Kafka Connect Connectors

Deploy, configure, and control the lifecycle of Kafka Connect connectors as code.

This guide shows how to manage Kafka Connect connectors with Jikkou. For the full resource specification, see the KafkaConnector reference.

Before you begin

  • One or more reachable Kafka Connect clusters.
  • Each cluster declared under the kafkaConnect.clusters[] setting in your Jikkou configuration — see the Kafka Connect provider configuration.

1. Describe a connector

The kafka.jikkou.io/connect-cluster label selects which configured cluster the connector is created in.

file: kafka-connector-filestream-sink.yaml

---
apiVersion: "kafka.jikkou.io/v1beta1"
kind: "KafkaConnector"
metadata:
  name: "local-file-sink"
  labels:
    kafka.jikkou.io/connect-cluster: "my-connect-cluster"
spec:
  connectorClass: "FileStreamSink"
  tasksMax: 1
  config:
    file: "/tmp/test.sink.txt"
    topics: "connect-test"
  state: "running"

2. Preview and apply

jikkou apply --files ./kafka-connector-filestream-sink.yaml --dry-run   # review
jikkou apply --files ./kafka-connector-filestream-sink.yaml             # apply

3. Control the connector lifecycle

Set spec.state and re-apply to change the runtime state of a connector:

  • running — connector and tasks are active (default).
  • paused — message processing is paused until resumed.
  • stopped — connector and tasks are shut down; the config is kept.

4. Inspect connector status

jikkou get kafkaconnectors --expand-status

The status.connectorStatus block reports the live state of the connector and its tasks as returned by the Kafka Connect REST API.

6 - Manage Apache Iceberg Tables

Create Iceberg namespaces and tables, and evolve table schemas safely, as code.

This guide shows how to manage Apache Iceberg namespaces and tables with Jikkou, including safe schema evolution. For the full resource specification, see the Iceberg Table reference.

Before you begin

  • Access to an Iceberg catalog (REST, Hive, JDBC, Glue, …) and its backing storage.
  • A Jikkou context configured with the Iceberg provider — see the Apache Iceberg provider configuration.

1. Create a namespace

file: iceberg-namespace.yaml

---
apiVersion: "iceberg.jikkou.io/v1beta1"
kind: "IcebergNamespace"
metadata:
  name: "analytics.events"
jikkou apply --files ./iceberg-namespace.yaml --dry-run   # review
jikkou apply --files ./iceberg-namespace.yaml             # apply

2. Create a table

file: iceberg-page-views.yaml

---
apiVersion: "iceberg.jikkou.io/v1beta1"
kind: "IcebergTable"
metadata:
  name: "analytics.events.page_views"
spec:
  schema:
    columns:
      - name: "event_id"
        type: "uuid"
        required: true
      - name: "user_id"
        type: "long"
        required: true
      - name: "page_url"
        type: "string"
        required: true
      - name: "event_time"
        type: "timestamptz"
        required: true
  partitionFields:
    - sourceColumn: "event_time"
      transform: "day"
  sortFields:
    - column: "event_time"
      direction: "asc"
  properties:
    write.format.default: "parquet"
    write.parquet.compression-codec: "zstd"
jikkou apply --files ./iceberg-page-views.yaml

3. Evolve the schema safely

To add, update, or drop columns, edit the resource and re-apply. Jikkou performs safe schema evolution and preserves Iceberg field IDs.

To rename a column without breaking existing readers, set previousName to the old name instead of dropping and re-adding it:

columns:
  - name: "user_identifier"   # new name
    previousName: "user_id"   # triggers a rename, not drop+add
    type: "long"
    required: true

By default Jikkou rejects unsafe type changes (e.g. string → int). Safe promotions such as int → long are allowed. To force an incompatible change on a single resource, set the annotation iceberg.jikkou.io/allow-incompatible-changes: "true".

Manage many tables at once

Use an IcebergTableList (handy with templating) to define multiple tables in a single file.

7 - Back Up and Restore Configuration

Export the current state of a cluster to YAML for backup or replication, then restore it elsewhere.

Because Jikkou is stateless and uses your platform as the source of truth, you can export the live state of any managed resource to YAML. Those files can be version-controlled, used as a backup, or applied to another cluster to replicate its configuration.

Before you begin

  • A Jikkou context configured for the source cluster — see Getting Started.

1. Export resources to a file

Use jikkou get <kind> with YAML output and redirect it to a file:

jikkou get kafkatopics -o yaml > topics-backup.yaml

The same pattern works for any managed resource kind. List the kinds available in your context — and the exact names accepted by get — with:

jikkou api-resources

Then export each kind to build a full snapshot, for example:

jikkou get kafkatopics -o yaml > topics-backup.yaml
jikkou get kafkaprincipalauthorizations -o yaml > acls-backup.yaml

2. Restore or replicate

Point Jikkou at the target cluster (e.g. switch context with jikkou config use-context <name>), then preview and apply the exported files:

jikkou apply --files ./topics-backup.yaml --dry-run   # review
jikkou apply --files ./topics-backup.yaml             # apply

This same flow lets you replicate configuration from one cluster to another: export from the source, switch context, and apply to the target.

Automate periodic backups

Run the export commands on a schedule (e.g. a cron job or a CI pipeline) and commit the output to a Git repository to keep a versioned history of your cluster configuration. See Automating for running Jikkou in CI/CD.

8 - Enforce Governance Policies

Use ValidatingResourcePolicy to enforce organizational rules on resources and changes with CEL.

A ValidatingResourcePolicy is a declarative, reusable way to enforce governance rules across any resource using Google CEL expressions. Use it to block destructive operations, enforce limits (partitions, replication factor), or require naming and metadata conventions.

For the full specification, see the ValidatingResourcePolicy reference. For the broader picture, see Validations.

Before you begin

1. Write a policy

A policy selects the resources it applies to and defines rules. Each rule’s expression is a CEL assertion that must hold for the resource to be valid: the rule fails when the expression evaluates to false (the same convention as Kubernetes ValidatingAdmissionPolicy). The failurePolicy decides what happens on failure:

  • FAIL: abort the operation with an error.
  • FILTER: silently drop the invalid resource(s) and continue.
  • CONTINUE: report the violation but let the resource proceed. Useful to introduce a new rule in “warning mode” before making it blocking.

file: policy-topics.yaml

---
apiVersion: core.jikkou.io/v1
kind: ValidatingResourcePolicy
metadata:
  name: KafkaTopicPolicy
spec:
  failurePolicy: FAIL
  selector:
    matchResources:
      - kind: KafkaTopic
  rules:
    - name: MaxTopicPartitions
      expression: "resource.spec.partitions <= 50"
      messageExpression: "'Topic partitions MUST be <= 50, but was: ' + string(resource.spec.partitions)"
    - name: MinTopicPartitions
      expression: "resource.spec.partitions >= 3"
      message: "Topic must have at least 3 partitions"

2. Apply resources with the policy

Policies are transient resources: pass the policy file alongside the resources being validated. Jikkou evaluates the policy during reconciliation.

jikkou apply --files ./kafka-topics.yaml --files ./policy-topics.yaml --dry-run

If a topic violates a rule, a FAIL policy stops the run and prints the rule’s message.

Block destructive operations

Policies can match change resources (e.g. KafkaTopicChange) to control operations. This example filters out delete operations on topics so they are never executed:

---
apiVersion: core.jikkou.io/v1
kind: ValidatingResourcePolicy
metadata:
  name: BlockTopicDeletes
spec:
  failurePolicy: FILTER
  selector:
    matchResources:
      - kind: KafkaTopicChange
  rules:
    - name: FilterDeleteOperation
      expression: "resource.spec.op != 'DELETE'"
      messageExpression: "'Operation ' + resource.spec.op + ' on topics is not authorized'"

Target a subset of resources

Combine matchResources, matchLabels, and matchExpressions (with matchingStrategy: ALL or ANY) to scope a policy. For example, apply it only to topics in the prod environment:

selector:
  matchingStrategy: ALL
  matchResources:
    - kind: KafkaTopic
  matchLabels:
    - key: environment
      operator: In
      values: ["prod"]

Policy library

Ready-made policies you can copy and adapt live in examples/policies/:

PolicyWhat it enforces
topic-naming-convention.yamlTopic names follow a convention (kebab-case by default; adapt the regex)
topic-min-insync-replicas.yamlmin.insync.replicas is set explicitly and is at least 2
topic-min-replication-factor.yamlReplication factor is declared and at least 3
topic-partition-limits.yamlPartition count stays within platform bounds (3 to 50 by default)
require-owner-label.yamlEvery topic carries an owner label
block-topic-deletes.yamlReconciliation may never delete a topic (matches change resources)

Centrally enforce policies for all teams

Passing policy files on every command works for one team, but a platform team usually wants policies applied to every run, no matter which files an application team passes. Configure a resource repository in the shared Jikkou context: repository resources are injected automatically into each execution.

jikkou {
  repositories = [
    {
      name = "platform-policies"
      type = io.jikkou.core.repository.GitHubResourceRepository
      config {
        repository = "my-org/kafka-platform-policies"
        branch = "main"
        paths = [ "policies/" ]
        # Access token for private repositories
        token = ${?GITHUB_TOKEN}
      }
    }
  ]
}

With this configuration in the context used by CI (or by the Jikkou API server), an application team running jikkou apply -f ./my-topics.yaml gets the platform policies evaluated on every resource and every change, without ever seeing the policy files. Updating a rule is a pull request on the central policies repository, immediately effective for all teams.

9 - Manage a Fleet of Kafka Clusters

Apply the same resource definitions across multiple Kafka clusters and providers in one command, with per-cluster results.

Most Kafka estates are fleets: a production cluster per region, staging, and often a mix of on-premises and managed services. Jikkou applies one declarative model across all of them: define each cluster as a named provider instance, group them, and target the group in one command.

Before you begin

1. Declare one provider instance per cluster

Each cluster is a named entry under provider, all sharing the same provider type:

jikkou {
  provider.kafka-prod-eu {
    type = io.jikkou.kafka.KafkaExtensionProvider
    config {
      client {
        bootstrap.servers = "kafka-eu.internal:9092"
      }
    }
  }
  provider.kafka-prod-us {
    type = io.jikkou.kafka.KafkaExtensionProvider
    config {
      client {
        bootstrap.servers = "kafka-us.internal:9092"
      }
    }
  }
  provider.kafka-staging {
    type = io.jikkou.kafka.KafkaExtensionProvider
    config {
      client {
        bootstrap.servers = "kafka-staging.internal:9092"
      }
    }
  }

  # Named groups for batch operations
  provider-groups {
    prod = ["kafka-prod-eu", "kafka-prod-us"]
  }
}

2. Target the fleet

The three selection flags are mutually exclusive:

# One cluster
jikkou apply -f ./resources --provider kafka-prod-eu

# A named group
jikkou apply -f ./resources --provider-group prod

# Every registered instance
jikkou apply -f ./resources --provider-all

Multi-provider runs are fail-fast by default: the first failing cluster aborts the run. Add --continue-on-error to keep going and get results for the remaining clusters.

3. Read per-cluster results

Results are reported per provider. In TEXT output, tasks are grouped under a provider header:

PROVIDER [kafka-prod-eu] *******************************************************
TASK [CREATE] Create a new topic orders-events (partitions=6, replicas=3) - CHANGED
PROVIDER [kafka-prod-us] *******************************************************
TASK [CREATE] Create a new topic orders-events (partitions=6, replicas=3) - CHANGED
EXECUTION in 3s 421ms
ok : 0, created : 2, altered : 0, deleted : 0 failed : 0

In JSON or YAML output, every change carries the jikkou.io/provider annotation, so results stay attributable when piped into other tools:

{
  "change": {
    "metadata": {
      "annotations": {
        "jikkou.io/provider": "kafka-prod-eu"
      }
    }
  }
}

Fleet-wide drift detection

jikkou diff accepts the same provider flags, so a scheduled CI job can check the whole fleet at once and tell you which cluster drifted:

jikkou diff -f ./resources --provider-group prod --fail-on-changes

See Detect configuration drift for the full CI setup.

10 - Migration

Step-by-step upgrade guides between Jikkou versions.

This section collects upgrade guides for major and breaking releases. If you’re moving between minor versions, the release notes usually contain everything you need.

10.1 - Migrating to Jikkou 1.0

Step-by-step upgrade guide from Jikkou 0.37.x to 1.0.0.

Jikkou 1.0.0 is a major release. The good news: the project’s first real breaking change — the move from io.streamthoughts.jikkou.* to io.jikkou.* — ships with a runtime deprecation shim, so most existing setups will run unchanged with warnings while you migrate at your own pace.

This guide walks through the upgrade end to end.

Before You Upgrade

A short checklist before you start:

  1. Pin your current version. Make sure your CI and any automation reference 0.37.3 (or whichever 0.37.x you run today) explicitly, not latest, so you can roll back fast.
  2. Back up your configurations. Commit any uncommitted Jikkou configuration and resource files. The migration is mechanical, but a clean baseline makes review easier.
  3. Plan a window. The shim means you don’t need downtime, but if you operate Jikkou as a service (jikkou-api-server), the upgrade is a normal rolling deploy.
  4. Read the v1.0.0 release notes. This guide is focused on change recipes; the release notes explain the why.

1. Update Maven / Gradle Coordinates

The Maven group changed from io.streamthoughts to io.jikkou. Artifact names are unchanged.

Maven

<!-- Before -->
<dependency>
  <groupId>io.streamthoughts</groupId>
  <artifactId>jikkou-core</artifactId>
  <version>0.37.3</version>
</dependency>

<!-- After -->
<dependency>
  <groupId>io.jikkou</groupId>
  <artifactId>jikkou-core</artifactId>
  <version>1.0.0</version>
</dependency>

Gradle

// Before
implementation("io.streamthoughts:jikkou-core:0.37.3")

// After
implementation("io.jikkou:jikkou-core:1.0.0")

If you depend on multiple Jikkou modules (jikkou-extension-rest-client, individual providers, etc.), update them all in one pass — they all moved together.

2. Rename Java Imports

If you maintain custom extensions, providers, or any Java code that imports Jikkou classes, replace the package prefix:

io.streamthoughts.jikkou.   →   io.jikkou.

With your IDE. Use the project-wide find-and-replace, scoped to *.java files. IntelliJ’s “Refactor → Rename” on the package root handles imports and pom.xml references in one step.

With sed (POSIX-friendly):

# From the repo root
git ls-files '*.java' '*.kt' '*.scala' \
  | xargs sed -i 's|io\.streamthoughts\.jikkou|io.jikkou|g'

Don’t rename your own packages. Only the prefix io.streamthoughts.jikkou.* belonging to Jikkou itself moved.

You don’t have to do this immediately. The runtime keeps resolving old class names through a deprecation shim and logs a warning. This means a staged rollout is safe: upgrade the dependency first, observe warnings in your logs, then schedule the import rename. The shim is scheduled for removal in 1.1.0.

3. Migrate Off Deprecated JikkouApi Overloads

Four JikkouApi overloads that take a raw Configuration have been deprecated since 0.37.0 (@Deprecated(forRemoval = true)) and will be removed in a future release. If you have custom Java code calling them, switch to the GetContext / ListContext builders:

DeprecatedReplacement
getResource(Class<?>, String, Configuration)getResource(ResourceType, String, GetContext)
getResource(ResourceType, String, Configuration)getResource(ResourceType, String, GetContext)
listResources(Class<?>, Selector, Configuration)listResources(ResourceType, ListContext)
listResources(ResourceType, Selector, Configuration)listResources(ResourceType, ListContext)

Recipe:

// Before
KafkaTopic topic = api.getResource(KafkaTopic.class, "events", configuration);

ResourceList<KafkaTopic> topics = api.listResources(
    KafkaTopic.class, selector, configuration);

// After
KafkaTopic topic = api.getResource(
    ResourceType.of(KafkaTopic.class),
    "events",
    GetContext.builder().configuration(configuration).build()
);

ResourceList<KafkaTopic> topics = api.listResources(
    ResourceType.of(KafkaTopic.class),
    ListContext.builder().selector(selector).configuration(configuration).build()
);

The new context objects also accept a provider (string) — that’s how you target a specific provider instance when you have several configured.

4. CLI Changes

get is now grouped by provider

jikkou get subcommands are organised under their provider. The canonical form is now:

jikkou get kafka topics
jikkou get kafka acls
jikkou get schema-registry subjects

Existing scripts that call the old flat form (jikkou get topics, jikkou get kafkatopics, jikkou get kt, …) still work — the old names are registered as hidden, deprecated subcommands that print a deprecation notice on each invocation. Plan to switch your scripts to the provider-grouped form before 1.1.0.

New flags on reconciliation commands

apply, create, update, patch, replace, delete, and diff accept three new options for multi-provider setups:

FlagPurpose
--provider-allApply to every registered provider of the matching type.
--provider-group <name>Apply to a named provider group (configured under jikkou.provider-groups).
--continue-on-errorContinue the batch when one provider fails (default: fail-fast).

--provider, --provider-all, and --provider-group are mutually exclusive. None of them are required: if you have a single provider of each type, your existing commands keep working unchanged.

For a complete walkthrough (configuration, per-cluster results, fleet-wide drift checks), see Manage a fleet of Kafka clusters.

Output format options

-o/--output now accepts JSON, YAML, or TABLE on list and get commands.

5. REST API Additions

ResourceReconcileRequest accepts two new optional fields:

{
  "resources": [ ... ],
  "providers": ["kafka-prod-eu", "kafka-prod-us"],
  "continueOnError": true
}

Both fields are additive. Existing clients that omit them are unaffected.

6. Verify the Upgrade

After updating coordinates and (optionally) imports:

# Confirm the version
jikkou --version

# Check that resources still parse and providers still load
jikkou api-providers list
jikkou api-resources

# Validate your manifests against the running providers
jikkou validate --files <your-manifests>

If you’re running custom extensions, watch the logs on first start for Class name 'io.streamthoughts.jikkou.…' is deprecated warnings — those are your remaining import-rename targets.

7. Rolling Back

If something goes wrong, revert the coordinate change to fall back to 0.37.3. Pin to the previous version via the original group:

<groupId>io.streamthoughts</groupId>
<artifactId>jikkou-core</artifactId>
<version>0.37.3</version>

Or download the binary from the v0.37.3 GitHub release.

Need Help?