Stream committed Informix changes to Kafka, without touching the engine.
A log-based change data capture connector for IBM Informix, built on the model PostgreSQL shops know as Debezium. It reads committed row changes from the Informix logical log and publishes one message per change to Apache Kafka — keyed by primary key, in a change-envelope format consumers already understand. It runs entirely as an external process, so streaming load never competes with transactional work, and it checkpoints its log position so a restart resumes where it left off. Verified against live Informix 14 and 15 engines.
Log-based, not trigger-based
Capture reads the committed change stream from the Informix logical log through the engine's own change data capture API. There are no triggers to install and no application changes to make.
Outside the engine by design
The connector is a standalone process reading the log through IBM's change-stream client. It carries no native code in the server and never competes with the database for CPU.
Checkpointed, so restarts resume
The connector persists its last committed log position at every commit. On restart it resumes from that checkpoint instead of re-reading the stream from zero.
A change envelope consumers know
Each change is published as a JSON envelope of the same shape Debezium emits — op, source, before, after, ts_ms — so tooling written against that shape works unchanged.
How change capture reaches Kafka
What the connector does
Point the connector at a logged Informix database and a list of
tables. From that moment, every committed INSERT,
UPDATE and DELETE on those tables becomes
a Kafka event. There are no triggers, no user-defined routines and
no application changes: capture happens outside the engine, reading
the logical log through the standard Informix change data capture
API.
This is the model PostgreSQL made routine — logical decoding streamed to Kafka through Debezium — brought to Informix with the same properties. Informix has always had the raw capability, a change data capture interface over its logical log; what was missing was a supported way to land that stream on Kafka. This connector is that piece. It does for Informix what Debezium does for PostgreSQL.
How the capture works
From the logical log to a Kafka topic. Each step preserves transactional truth.
Reads the committed change stream
The connector opens a capture session, enables full-row logging on the captured tables, and reads change records from the logical log. It sees a transaction's operation records followed by a COMMIT or ROLLBACK, so it works only with committed data.
A before / after envelope per change
Each change becomes one JSON message. An insert carries the new row in after; an update carries both the old row in before and the new row in after; a delete carries the old row in before. Values convert faithfully — numbers stay numeric, temporal types become ISO strings, SQL NULL becomes JSON null.
Keyed by primary key
The Kafka message key is the row's primary key, so a row's changes land in order on the same partition, and a log-compacted topic keeps only the latest state per key. The default topic is cdc.<database>.<table>, overridable per table.
Tombstones on delete
A delete emits the before-image envelope and then a tombstone — the primary key with a null value — so a compacted topic can drop the deleted key entirely. Consumers built for Debezium tombstones behave as they already do.
Transaction-consistent, no dual-write
An event exists if and only if its transaction committed. The connector buffers each transaction's changes and produces them only on its COMMIT; a rolled-back transaction is discarded and produces nothing. There is no dual-write problem to solve and no phantom events to filter.
Checkpoints its log position
On each commit the connector flushes the producer, waits until Kafka has durably stored every record in the transaction, and only then advances its log-position checkpoint. Delivery is at-least-once; the checkpoint never runs ahead of what Kafka holds. On restart it resumes from the saved position.
Hand-built database-to-Kafka integration vs log-based CDC
| A hand-built integration | The ifxtools connector | |
|---|---|---|
| Mechanism | Triggers, polling, or the application writing to both the database and Kafka | ✓ Reads the committed change stream from the Informix logical log |
| Consistency | Dual-write risk — the database commit and the Kafka write can diverge on failure | ✓ An event exists only if its transaction committed — no dual-write problem |
| Application changes | Business code, triggers or a relay to write, maintain and operate | ✓ None. No triggers, no user-defined routines, no application edits |
| Ordering | Assembled by hand, easy to get wrong under concurrency | ✓ Per-key ordering from the primary-key message key, preserved by construction |
| Deletes | Often lost — a deleted row leaves nothing to poll or trigger on | ✓ A delete envelope plus a tombstone, so compacted topics stay correct |
| Restart | Bespoke offset tracking, or re-processing from the beginning | ✓ Checkpoints its log position at every commit and resumes from it |
| Load on the engine | Trigger and polling overhead falls on the transactional path | ✓ Capture runs outside the engine and does not compete for CPU |
What teams use it for
One capture stream, several downstream jobs. Each is fed off the log without changing the application.
Analytics and data-lake feeds
Land row-level changes onto Kafka and into the analytical tier or data lake continuously, instead of running nightly extracts against the operational engine. The stream reflects committed state, so the warehouse never diverges from the source.
Replication and cache offload
Keep a downstream copy, a search index or a cache in step with Informix. Each change is published as it commits, keyed by primary key, so consumers apply updates in the right order and evict or refresh the exact keys that changed.
Event-driven integration
Turn business facts already born as row changes — order placed, payment captured, stock moved — into Kafka events that other systems subscribe to. Integration becomes a consumer concern, not another write path bolted onto the application.
The transactional outbox
When a single business event spans several writes and needs a custom payload, the application inserts a row into an ordinary outbox table in the same transaction as the business change. The connector captures that table, so the event commits atomically with the change and streams to Kafka with no trigger and no relay to operate.
Before you put it in front of a production estate.
What does capture cost the engine?
The connector runs as an external process. It reads the logical log through the Informix change data capture API rather than executing anything on the transactional path, so it does not compete with the database for CPU and carries no native code in the server. The one thing it enables in the engine is full-row logging on the captured tables, which the connector turns on at startup and turns back off on a clean shutdown.
What are the ordering and delivery guarantees?
A row's changes are keyed by its primary key, and Kafka preserves order within a partition, so changes to a given row are delivered in order. Delivery is at-least-once: on each commit the connector flushes the producer and only then advances its checkpoint, so the checkpoint never runs ahead of what Kafka has durably stored. Each envelope carries a source sequence number, so a consumer that needs effectively-once processing deduplicates on it.
How does it stay consistent with the database — no phantom or missing events?
Capture reads only committed transactions. The connector buffers a transaction's changes and produces them on its COMMIT; a rolled-back transaction is discarded and produces nothing. An event therefore exists if and only if its transaction committed, which removes the dual-write problem that hand-built integrations have to work around.
Which tables and column types can it capture?
You choose the tables — capture is a comma-separated list of owner.table entries, with an optional per-table topic override. The database must be logged, since the logical log is the source. Informix change data capture does not stream large-object and long-character columns — BYTE, TEXT, LVARCHAR, BLOB and CLOB — and the connector excludes those from the captured column list automatically.
What about existing rows — does it snapshot the table first?
Today the connector captures changes from the moment it starts; it does not perform an initial snapshot of rows that already exist. Estates that need the current contents seeded into Kafka load them separately before enabling capture. A consistent initial snapshot in the Debezium style is the connector's main planned addition.
Can it publish to an authenticated, encrypted broker?
Yes. The connector uses the standard Java Kafka client, so any producer property — security protocol, SASL mechanism, JAAS configuration, truststore location, compression — is passed straight through from its configuration file. Producing to a SASL_SSL broker over TLS is verified by the test suite.
How is it deployed and configured?
It is a single self-contained pure-Java jar — no Informix Client SDK and no native libraries; the JDBC driver and the change-stream client are bundled. It is configured by one .properties file passed as its argument, with no SQL registration and no in-engine objects to create. The natural shape is a sidecar next to Informix, given a stop grace period so it can disable full-row logging cleanly on shutdown.
Which Informix versions is it proven on?
Informix 14 and 15. Capture, the transactional buffering, resumable checkpointing and authenticated TLS delivery are exercised against live Informix 14 and 15 engines in an automated suite that runs on every change.