Reach for the outbox pattern when a service owns a relational database and must publish events or call other services as part of the same logical operation, and losing or duplicating those events would corrupt downstream state. Order processing, payments, inventory, and any saga step are typical fits.
The cost is extra moving parts. You now run a relay or a CDC pipeline, monitor outbox lag, and clean up old rows so the table does not grow without bound. A polling relay adds query load and a small delay, often hundreds of milliseconds to a few seconds, between the commit and the event landing on the broker. CDC removes the polling load but adds operational weight from running Debezium and Kafka Connect.
It is also not a magic bullet for ordering. The relay preserves the order rows were committed in if you publish by created order and use a single partition key per aggregate, but with multiple workers or partitions you can reorder events, so design consumers to tolerate that.
If your service does not have a transactional database, or you genuinely need exactly-once cross-system writes, the outbox does not apply directly. In that case people reach for two-phase commit, which is slower and brittle, or accept at-least-once with idempotency, which is what the outbox embraces.