Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Quick Start

mqb copy SOURCE TARGET moves data between two endpoints described as URIs. The scheme picks the connector; ?query=params configure it. The existing --from SOURCE --to TARGET form is equivalent and remains supported.

mqb copy \
  'postgres://localhost/app?table=users' \
  'clickhouse://localhost:8123?table=users&database=analytics'

This copies every row currently in app.users (PostgreSQL) into analytics.users (ClickHouse). No config file, no UI — just a source and a destination. Add --drain to exit once the source is empty instead of running as a continuous bridge (see Continuous vs. one-shot below).

The common copy controls are deliberately small:

mqb copy SOURCE TARGET [--filter EXPR] [--resume] [--drain]

--filter evaluates a readable expression against each top-level JSON payload, for example amount > 100 or status == "paid". A false result intentionally drops and acknowledges the message; malformed JSON and invalid expressions are errors, while a field that is absent or not a scalar counts as no match and is warned about once. It is an in-process filter and is not translated into a database query. Filtering into cloud object storage also changes how the objects are named — see Filtering.

--resume asks the source to use its native durable position and fails before the route starts when that is not safe. The generated state identity includes the credential-redacted source, destination, and filter, so changing pipeline semantics starts a new checkpoint while rotating a password does not.

The examples below are complete, working commands. Each links to the full connector page for that endpoint, which lists every available option; the generated URL reference is the authoritative source for every parameter’s type, default, and description.

PostgreSQL → ClickHouse

mqb copy --drain \
  --from 'postgres://user:pass@localhost/app?table=orders' \
  --to 'clickhouse://localhost:8123?table=orders&database=analytics'

Reads all rows from the orders table and bulk-inserts them into ClickHouse’s HTTP interface. For a resumable non-destructive scan, add &cursor_column=id on --from and pass --resume; the CLI supplies the stable cursor id and the SQL source stores the checkpoint in its own database. An explicit cursor_id or checkpoint_store in the URI still takes precedence. See PostgreSQL and ClickHouse.

Filtered, resumable Kafka copy

mqb copy \
  'kafka://localhost:9092?topic=orders' \
  'postgres://localhost/app?table=orders' \
  --filter 'status == "paid"' \
  --resume

The generated Kafka consumer group is stable for this source, destination, and filter. Kafka offsets advance only after the destination succeeds, or after a message is intentionally filtered out.

PostgreSQL CDC → PostgreSQL

mqb copy \
  --from 'postgres-cdc://user:pass@localhost/app?publication=mqb_pub&slot_name=mqb_slot' \
  --to 'postgres://user:pass@otherhost/replica?table=orders&auto_create_table=true'

Streams inserts/updates/deletes from a PostgreSQL logical-replication publication into another PostgreSQL table, continuously (CDC is a change stream, so this command doesn’t drain — run it as a long-lived process). See PostgreSQL CDC.

MQTT → Kafka

mqb copy \
  --from mqtt://broker.local:1883?topic=sensors/+/temperature \
  --to kafka://kafka.local:9092?topic=sensor-readings

Subscribes to an MQTT topic (wildcards supported) and republishes every message to a Kafka topic, continuously. See MQTT and Kafka.

RabbitMQ → HTTP

mqb copy \
  --from rabbitmq://guest:guest@localhost:5672/%2f?queue=orders \
  --to http://internal-api.local/ingest?method=POST

Consumes messages from a RabbitMQ queue and POSTs each one to an HTTP endpoint, continuously. See RabbitMQ and HTTP.

File (CSV) → MongoDB

mqb copy --drain \
  --from file:///data/customers.csv?format=csv \
  --to 'mongodb://localhost?database=app&collection=customers'

Reads a CSV file (first row = header) and inserts one document per row into a MongoDB collection, then exits since the source is a finite file. See File and MongoDB.

Continuous vs. one-shot

Without --drain, copy runs as a continuous bridge until Ctrl-C — the right mode for message brokers (MQTT, Kafka, RabbitMQ) and CDC sources, which never “end”. With --drain, copy exits once the source yields an empty batch — the right mode for finite sources (a file, or a full-table read from a database). --concurrency and --batch-size tune throughput on both modes.

Escape hatch: driver options and full connection strings

Any query parameter that isn’t a recognised config field (e.g. sslmode, replicaSet) is left on the connection URL untouched, so driver-specific options just work — including object-typed fields like tls, which can never be set from a single scalar query param and so always stays on the URL (e.g. mongodb://host/?tls=true&database=appdb passes tls=true straight through to the MongoDB driver). If you already have a complete connection string (copied from elsewhere, or one whose own options would otherwise be mis-parsed as config), skip decomposition entirely and pass it verbatim with ?url=<url-encoded string>:

mqb copy \
  --from 'mongodb://_/?url=mongodb%3A%2F%2Fuser%3Apass%40host%2Fdb%3Ftls%3Dtrue&collection=orders' \
  --to null:

See the generated reference for each connector’s recognised field names.