Skip to main content
Conduktor logical topics are abstractions of real Kafka topics that provide additional functionality that’s not available by default. We offer the following types of logical topics:
  1. Alias topics are topics that can be accessed with a name (alias), but point to another, real topic behind the scenes. Alias topics can be very useful when you want to share topics but have sensitive naming conventions; or in scenarios where underlying topics might be frequently renamed.
  2. Concentrated topics transparently co-locate multiple topics in the same physical topic behind the scenes, acting as pointers to reduce costs on low-volume topics with large partition counts. They are completely transparent to consumers and producers and allow you to emulate different partition counts irrespective of the backing physical topic’s partition count.
  3. Topic views filter records from physical topics using SQL WHERE clauses. This is the recommended approach for filtering JSON data.
  4. SQL topics DEPRECATED use SQL language to query and filter an existing topic.
  5. CEL topics DEPRECATED another way to filter an existing topic using CEL expressions instead of SQL.

Alias topics

Alias topics act as pointers that target a specific physical topic, defined with the AliasTopic resource. One of Kafka’s limitations is that you can’t rename topics - an issue that is solved with alias topics. You can have a number of alias topics pointing to the same physical topic.

Use

manages an alias topic mapping in its internal configuration by registering a target physical topic. This topic will be presented to Kafka clients like a regular topic. However, all requests for this topic will be forwarded to the physical topic. This means that consumer groups, fetch and produce are shared. Also, the alias topic does not replace the original one. For example, if you create an alias topic applicationB_orders that’s pointing to a physical topic orders, a client that can access the physical topic would be able to see both topics.

Limitations

  • using delegated Kafka security SASL delegated security protocols aren’t supported.
  • Alias topics can’t reference another alias topic.

Concentrated topics

Occasionally, topics have to be created for logical, rather than technical reasons (e.g. to differentiate between business units) which can result in considerable overuse of Kafka resources. Conduktor’s topic concentration allows data from a set of topics to be represented on a single underlying topic. Clients connecting through Conduktor Gateway can use concentrated topics as usual without any additional configuration. For example, let’s say we have the following topics:
  • us_east_orders - 100 partitions
  • us_west_orders - 100 partitions
  • emea_orders - 100 partitions
  • latam_orders - 100 partitions
The total Kafka resource requirement is 400 partitions. With topic concentration, all of these topics can be concentrated to a single topic, using only 1/4 of resources:
  • concentrated_orders - 100 partitions

Configuration

Configure concentrated topics with a ConcentrationRule. For all available fields, see the ConcentrationRule resource reference.
To create concentrated topics, first deploy ConcentrationRule:
Then topics that match the ConcentrationRule spec.pattern:
Topic ConcentrationWe now have two concentrated topics (concentrated.topicA and concentrated.topicB) with partition counts of 3 and 4 respectively, mapped to a single physical topic (physical.topic) with three partitions.To ensure that consumers don’t consume messages from other partitions or from other concentrated topics, we store the concentrated partition and the concentrated topic name in the record headers. Gateway will automatically filter the messages that should be returned to the consumer.

Limitations

Consumer offsets

When consuming from a concentrated topic, messages and ordering is always preserved but any metadata calculations (primarily lag and message count) are unlikely to be as expected. This is because the associated metadata is from the backing Kafka topic, rather than the concentrated topic seen from the perspective of the consumer. This is a known limitation.

Compact and delete+compact topics

You can create concentrated topics with any cleanup.policy, but your ConcentrationRule has to have a backing topic for each of them, otherwise it won’t let you create the topic.
In this example, since the config for spec.deleteCompact is commented out, trying to create this topic will fail:
Backing topic cleanup policies are checked when you deploy a new ConcentrationRule. This prevents you from declaring a backing topic with a cleanup.policy of delete on the ConcentrationRule spec.physicalTopic.compact field.

Restricted topic configurations

The following list of topic properties are the only allowed properties for concentrated topics:
  • partitions
  • cleanup.policy
  • retention.ms
  • retention.bytes
  • delete.retention.ms
If any other configuration than the above is set, the topic creation will fail with an error. retention.ms and retention.bytes can be set to values lower or equal to the backing topic. If a user tries to create a topic with a higher value, topic creation will fail with an error:
This behavior can be altered with the flag spec.autoManaged.
With concentrated topics, the enforced retention policy is the physical topic’s retention policy, and not the policy requested at the concentrated topic creation time. The retention.ms and retention.bytes are not cleanup but retention guarantees.

Auto-managed backing topics

When autoManaged is enabled:
  • backing topics are automatically created with the default cluster configuration and partition count.
  • concentrated topics created with higher retention.ms and retention.bytes are allowed. This automatically extends the configuration of the backing topic.
Let’s check the backing topic retention on the physical cluster:
Let’s try to create a concentrated topic with a higher retention on Gateway:
Let’s review the backing topic again:
As we can see, the retention has been updated.
If one user requests a topic with infinite retention (retention.ms = -1), all the topics with the same cleanup policy associated with the rule will also inherit this extended configuration and have infinite retention.

Message count, lag and offset (in)correctness

By default, concentrated topic reports the offsets of their backing topics. This impacts the calculations of Lag and Message Count that relies on partition EndOffset and group CommittedOffset. Offset Incorrectness Any tooling will currently display the message count, and the lag relative to the EndOffset of the physical topic. This can create confusion for customers and applications that will see incorrect metrics. Gateway has an offsetCorrectness setting on ConcentrationRule that makes concentrated topics report virtual offsets, so that lag and message count read correctly. It is deprecated, and we don’t recommend enabling it.
spec.offsetCorrectness is deprecated as of v3.21.0 and is planned for removal in v3.24.0. Existing rules keep working, but Gateway now logs a single deprecation warning at startup listing the affected concentrated topics. Because of the limitations listed below, treat the physical-topic offsets described above as the supported behavior.
If you already have it enabled, the setting looks like this:
  • spec.offsetCorrectness only applies to concentrated topics with the cleanup.policy=delete
  • spec.offsetCorrectness is not retroactive on previously created concentrated topics

Stop using offset correction

If you have offsetCorrectness enabled in production, get in touch for support with this migration.

Known issues with offset correctness

There are three known issues with the offset correctness in concentrated topics: 1. Performance On startup, Gateway has to read the concentrated topic entirely before it’s available to consumers. The end-to-end latency is increased by up to 500 ms (or fetch.max.wait.ms, if non-default). 2. Memory Gateway consumes about ~250MB of heap memory per million records it’s read in concentrated topics. This value is not bound, so we don’t recommend offset correctness on high-volume topics, and recommend to size your JVM accordingly. 3. Unsupported Kafka API
  • DeleteRecords is not supported
  • Transactions are not supported
  • Only IsolationLevel.READ_UNCOMMITTED is supported (using IsolationLevel.READ_COMMITTED is undefined behavior)
  • Partition truncation (upon unclean.leader.election=true) may not be detected by consumers
Very slow consumer group edge case
Do not enable offset correctness when your topic has extended periods of inactivity.
When using topic concentration with offsetCorrectness enabled, there’s currently a limitation for consumer groups where the data in the topics is slow moving, and/or the consumer groups are not committing their offsets frequently. If a consumer group with a committed offset waits for the backing physical topic longer than the retention time (without committing a new offset), there’s a possibility for that consumer group to become blocked. In this scenario, a consumer group whose last committed offset has been removed from the topic, the group becomes blocked only if Gateway restarted before the next offset commit. If this limitation happens, the offsets for the affected consumer group will need to be manually reset for it to continue.

Topic views

Topic views provide non-materialized views of physical Kafka topics, similar to database views. They apply transformations to records as they’re consumed, without modifying the underlying data. Topic views support SQL-based filtering and projection on schema-less JSON, and SQL-based filtering on Avro, Protobuf and JSON-Schema records read through a schema registry connection. Support for additional transformations, for example CEL, is planned. See a topic view give one team a filtered, projected read of a topic:
Topic views are generally available from Gateway 3.20.0. Most topic views created in the 3.19.x tech preview keep working; those with invalid SQL are now rejected and have to be recreated with valid SQL.Existing consumer groups won’t work after the upgrade — recreate them with a group.id that follows the new convention (see Set the consumer group ID). A fresh group starts with no committed offsets. If you use Console, you can duplicate the existing group into the new name to carry your position over.
Topic views are configured as a dedicated Gateway resource, similar to alias topics.
Topic views are a replacement for SQL topics and CEL topics, which are deprecated. Topic views will be extended to cover all of their functionality, after which the plugins will be removed.
Prefer a hands-on walkthrough? Migrate a Kafka Streams transformer to a Topic View runs the whole before → after migration — creating the view, seeding offsets, and cutting a downstream consumer over with no reprocessing.

How it works

When a consumer fetches from a topic view, Gateway:
  1. Reads records from the underlying physical topic
  2. Applies the configured transformation to filter or modify each record
  3. Returns the resulting records to the consumer
Schema-encoded records whose schema ID is stored in a record header, the format introduced in Confluent Platform 8.2, require Gateway 3.21.0 or later.
Consumer offsets are committed against the physical topic because the topic view doesn’t exist in Kafka’s __consumer_offsets. This means you may see gaps in offset numbers when records are filtered out. The committed offset is always the offset of the last record in the batch, regardless of whether that record was filtered out.
Topic views are read-only by design, but Gateway doesn’t enforce this yet. Producing to a topic view isn’t blocked, so avoid it until enforcement is added.

Configuration

Configure topic views using the Gateway REST API or Conduktor CLI. For all available fields, see the TopicView resource reference.

SQL transformation

When using transformation.type: sql, topic views filter and transform records using SQL syntax. The transformation uses a subset of SQL that will be extended in future releases.
Topic names with dash - characters have to be double quoted, as the dash is not a valid character for a SQL name. For example, if you have a topic our-orders, use SELECT * FROM "our-orders" WHERE ...

Projection

Use the SELECT clause to reshape records by renaming fields, selecting a subset of fields, computing new values, or including record metadata.
Projection applies to views over schema-less JSON. A view that names a schema registry connection has to use SELECT * — see read schema-encoded topics.

CASE expressions

A CASE expression maps conditions to fixed values:
Gateway takes the first branch whose condition holds, and the ELSE value when none do. The following rules apply:
  • Each WHEN condition takes the same predicates as a WHERE clause, listed under supported predicates below.
  • THEN and ELSE values have to be literals: a string, number, boolean, date, timestamp or time. A field reference or a computed expression isn’t supported.
  • ELSE is required. Without it, a record that matches no branch has no value to project.
  • The switch form CASE department WHEN 'sales' THEN … isn’t supported. Write the comparison out in each WHEN instead.
  • A CASE can’t sit inside a JSON_OBJECT value.

Nested output with JSON_OBJECT

Projection is flat by default: SELECT a AS x, b produces {"x": ..., "b": ...}, so a dotted path lands under a flat key. Use JSON_OBJECT to emit nested JSON instead:
For this record:
JSON_OBJECT projects:
  • Each JSON_OBJECT value is a field reference or another JSON_OBJECT, nested to any depth.
  • Keys within one object have to be unique.
  • When the whole SELECT is a single top-level JSON_OBJECT, that object becomes the record value and its alias (AS payload) is ignored. Alongside other columns, it nests under its own alias instead.
  • An absent or null field is emitted as null — the key is always kept.
  • Available for schema-less JSON only.

Supported predicates

  • =, >, >=, <, <=, <> and != (standard comparison operators)
  • REGEXP (regular expression matching)
  • IN / NOT IN with a literal list, e.g. country IN ('UK', 'US')
  • AND operator for combining multiple conditions (OR is not yet supported)
  • Parentheses around a single condition, e.g. (country = 'UK') AND (amount > 10)

Regular expression matching

Use REGEXP for pattern matching. SQL LIKE is not supported, so use REGEXP in place of LIKE wildcards:

Date and time values

A record’s date and time values are typically stored as strings, since JSON has no native date or time type. To compare them chronologically rather than lexically, write the comparison value as a JDBC escape literal so Gateway reads it as a date or time:
  • Date: {d 'YYYY-MM-DD'}
  • Time: {t 'HH:MM:SS'}
  • Timestamp: {ts 'YYYY-MM-DD HH:MM:SS'}
Gateway parses the record’s string field into the same type and compares the two chronologically. If the field value can’t be parsed as that type, the record doesn’t match:
Use the JDBC escape form for date and time comparisons. Two alternatives don’t work:
  • A plain string literal (such as event_at > '2026-01-01 12:34:56') is compared lexicographically, not chronologically. Gateway doesn’t error, but range results can be wrong across mixed formats.
  • The ANSI SQL forms DATE '2026-01-01' and TIMESTAMP '2026-01-01 12:34:56' aren’t supported.

Nested field access

Access nested JSON fields using dot notation:

Array index access

Access array elements using bracket notation with backticks:
Backticks are required around field names with array index notation.

Record key, headers, and Kafka metadata

In addition to record value fields, you can reference the record key, headers, and Kafka metadata:
record.timestamp is milliseconds since the epoch. Header names that contain . aren’t supported in this syntax.

Virtual Cluster topic names

If you use Virtual Clusters, the topic name in the FROM clause has to be the full physical name on the backing cluster, including the Virtual Cluster prefix. This applies even when the topic view targets a topic in the same Virtual Cluster. For example, a topic view in the vc-alice Virtual Cluster that targets the orders topic in that cluster reads from the physical name vc-aliceorders:

Unsupported syntax

Topic views support only the SQL features documented above, and Gateway rejects anything else when you create or update the view. The documented set is the contract: the list below names what people reach for most often, not every rejected construct. Operators:
  • OR operator (planned)
  • NOT, including NOT REGEXP and NOT LIKE
  • LIKE with wildcards
  • BETWEEN
  • IS NULL / IS NOT NULL
  • EXISTS
  • String concatenation (||)
  • Numerical operators (+, -, *, / etc)
Functions:
  • String functions (UPPER, LOWER, CONCAT)
  • COALESCE
  • CAST
Query features:
  • JOIN, and more than one topic in FROM
  • Subqueries anywhere, including IN (SELECT …) and a subquery as the FROM item
  • A topic alias or other FROM modifier, such as FROM orders o or PIVOT
  • SELECT DISTINCT
  • LIMIT, OFFSET, FETCH and TOP
  • ORDER BY
  • GROUP BY and HAVING
  • WITH (common table expressions)
  • SELECT … INTO
  • Set operations (UNION, INTERSECT, EXCEPT, MINUS)
JSON expressions that resolve to more than one value:
  • path expressions returning an array or an object
  • Array wildcards: items[*].name or items.*.name
  • JSONPath filter expressions: items[?(@.price > 10)]
  • Slices (items[0:2]), index lists (items[0,1]), and recursive descent (..status)
If any of these SQL features would be useful for your use case, let your Conduktor support contact know.

Read schema-encoded topics

Schema registry external connections are a preview feature and subject to change, so reading schema-encoded topics is too — a topic view has no other way to reach a schema registry.
By default a topic view reads schema-less JSON. To read Avro, Protobuf or JSON-Schema records, set spec.schemaRegistryConnectionName to the name of a schema registry external connection:
Gateway decodes each record through that connection, applies the WHERE clause and returns the records that match.
A schema-backed topic view has to use SELECT *. A WHERE clause is still allowed, because it filters whole records rather than selecting columns. Gateway rejects a projection at create and update time:Column projection is not yet supported for schema-registry-backed topic views; use SELECT * with a WHERE clause.Views over schema-less JSON keep full projection support.
Gateway rejects an unknown connection name with 400 Bad Request when you create or update the view. Remove a connection a view already names and the view stays saved but stops serving traffic. See what happens at startup. Decoding still needs the registry while Gateway runs: it fetches any schema the connection hasn’t already cached. If the registry becomes unavailable, Gateway withholds the affected records and the consumer retries, rather than applying the view’s onError strategy — so a registry outage stalls the view instead of dropping records.

Error handling

The spec.onError field declares what Gateway should do when a record can’t be transformed (for example, the SQL doesn’t match the record structure). The field is required on every topic view and takes one of two values:
  • DROP — drop the failing record from the response and continue.
  • FAIL_FETCH — fail the fetch for that partition.

Set the consumer group ID

To consume from a topic view, include the view’s name in your consumer’s group.id, delimited by ::. The rest of the group.id is free-form, so you can keep your usual naming alongside the view name.
To read from more than one topic view with a single consumer, add each view name as a token:
Each view named in a group.id has to have a different backing topic. You can’t name two views of the same backing topic in the same group.id. This keeps consumers of different views in separate Kafka consumer groups. Without it, Kafka can split a backing topic’s partitions across views in the same group, and each consumer drops the records meant for the other, causing silent data loss. Gateway checks the group.id when a consumer joins a group or commits offsets, and rejects it with an INVALID_GROUP_ID error if it doesn’t follow this convention. The check also covers a topic view’s backing topic, whether read directly or through an alias, since that’s equivalent to reading the view. Concentrated topics are exempt, and a consumer that touches no topic view or backing topic is unaffected.
Requiring a specific group.id format is a temporary limitation. We plan to remove it in a future release, once Gateway supports the KIP-848 consumer group protocol.
For a worked example of migrating an existing consumer onto a view — including seeding its starting offsets — see the Kafka Streams → Topic View tutorial.

Planned features

Topic views apply SQL transformations to schema-less JSON, and SQL filtering to schema-encoded records. We plan to add:
  • More transformation types: CEL (Common Expression Language) and RSQL, alongside SQL.
  • Projection on schema-encoded records: selecting a subset of fields from Avro, Protobuf and JSON-Schema records, which today requires SELECT *.

SQL topics

SQL topics are deprecated as of Gateway v3.19.0. They will be removed once topic views support the remaining SQL topic functionality.
SQL topics are incompatible with incremental fetch sessions, and return incorrect results if you enable that feature. Topic views don’t have this limitation.
Conduktor Gateway’s SQL topic feature uses a SQL-like language to filter and project messages, based on a simple SQL statement:
This supports FetchResponse only (i.e., resulting topic is read-only): SELECT [list of fields] FROM [topic name] WHERE [field filter criteria]
Topic names with dash - characters have to be double quoted, as the dash is not a valid character for a SQL name. For example, if you have a topic our-orders, use SELECT * FROM "our-orders" WHERE ...
Other limitations:
  • With filter records based on more than one condition, only AND operator is supported
  • Supported predicates: =, >, >=, <, <=, <> and REGEXP (RegExp MySQL Operator)
  • Case expression is supported
  • Filtered by:
    • Record key (It supports SR):
      • Record key as string: - .. WHERE record.key = 'some thing'
      • Record key as schema: .. WHERE record.key.someValue.someChildValue = 'some thing'
    • Record value (It supports SR): .. WHERE $.someValue.someChildValue = 'some thing'
    • Partition: .. WHERE record.partition = 1
    • Timestamp: .. WHERE record.timestamp = 98717823712
    • Header: .. WHERE record.header.someHeaderKey = 'some thing'
    • Offset: .. WHERE record.offset = 1

Schemas and projections

If your data uses a schema, then it’s not possible to make use of the projection feature here because the resulting data will no longer match the original schema. For plain JSON topics, you can use the SELECT clause to alter the shape of the data returned; however, for schema’d data (Avro and Protobuf) you must not use a projection, i.e. the select should be in the form: SELECT * FROM ... Filtering with the where clause is still supported.

Configuration

Example

Schema registry with secured template

Filter topics with CEL

CEL topics are deprecated as of Gateway v3.17.0. They will be removed once topic views support CEL transformations.
CEL topics are incompatible with incremental fetch sessions, and return incorrect results if you enable that feature. Topic views don’t have this limitation.
Conduktor Gateway’s CEL topic feature uses CEL (Common Expression Language) expression to filter messages, based on a simple CEL expression in the form. Currently
  • Filtered by:
    • Record key (It supports SR):
      • Record key as string: - .. record.key == 'some thing'
      • Record key as schema: .. record.key.someValue.someChildValue == 'some thing'
    • Record value (It supports SR): .. record.value.someValue.someChildValue == 'some thing'
    • Partition: .. record.partition == 1
    • Timestamp: .. record.timestamp == 98717823712
    • Header: .. record.header.someHeaderKey == 'some thing'
    • Offset: .. record.offset == 1

Configuration

Example

Schema registry with secured template

Schema registry configuration

Schema-encoded records whose schema ID is stored in a record header, the format introduced in Confluent Platform 8.2, require Gateway 3.21.0 or later.
Gateway supports Confluent-like and AWS Glue schema registries. If you don’t supply a basicCredentials section for the AWS Glue schema registry, the client will attempt to find the connection information it needs from the environment (see AWS docs for details ) and the credentials required can be passed this way to Gateway as part of its core configuration. Read our blog about schema registry .