Every system architect eventually faces a fork in the road: should this workflow process data in discrete chunks or as a steady stream? The choice between batch and continuous architectures is not a matter of fashion—it shapes latency, cost, fault tolerance, and the very mental model your team uses to reason about the system. This guide maps the divergence, not as a checklist of features, but as a framework for matching workflow topology to operational reality.
We write for engineers who have seen both patterns in production and suspect their current choice might be suboptimal. You will leave with a structured way to evaluate the trade-offs, plus a few surprises about where each model silently fails.
Why This Fork Matters Now
Modern data pipelines and event-driven systems have blurred the line between batch and continuous. Streaming platforms like Kafka and Flink make continuous processing look easy, while orchestration tools like Airflow and Prefect have made batch workflows more reliable than ever. The result is a dangerous middle ground: teams adopt streaming because it sounds modern, only to discover they need exactly-once semantics for a nightly reconciliation job. Or they stick with batch and miss real-time alerts that could have prevented a cascading failure.
The stakes are higher than developer convenience. Batch and continuous architectures impose fundamentally different contracts on state, time, and failure. A batch job that fails at 95% can be retried from the last checkpoint; a continuous processor that crashes mid-stream may need to replay hours of data or accept gaps. Choosing the wrong model leads to either over-engineered infrastructure (running a full streaming cluster for a once-daily aggregation) or brittle workarounds (batching inside a stream processor to force transactional boundaries).
We have seen teams burn weeks on exactly this mismatch. One project built a continuous ingestion pipeline for sensor data, only to realize the downstream database could not handle concurrent upserts at the same rate—they ended up adding a batch buffer that essentially recreated a micro-batch architecture. Another team ran nightly batch jobs for a recommendation system, missing user behavior shifts that happened mid-day, costing them engagement. These are not edge cases; they are the natural consequence of treating workflow topology as an afterthought.
This guide is not a vendor comparison. We focus on the architectural properties that persist across implementations: latency profile, resource elasticity, error recovery, and state scoping. By the end, you should be able to look at a workflow requirement and immediately identify which pattern fits, and more importantly, which pattern will break first under pressure.
Who Should Read This
Software architects, senior engineers, and technical leads evaluating or migrating data pipelines. If you have ever argued about whether to use a queue or a cron job, this is for you.
Core Idea in Plain Language
A batch architecture processes work in discrete, scheduled chunks. Data accumulates over a window (an hour, a day, a 10,000-record buffer), and then a job runs to transform, analyze, or move that entire chunk as a unit. The key property is that the processing unit is a bounded set—you know exactly what you are working on, and you can retry the whole set if something fails.
A continuous architecture processes each piece of work as it arrives. There is no intentional accumulation; the system reacts to events in near-real time. The processing unit is a single event or a small micro-batch (often configurable, but the intent is low latency). State is maintained across events, often in memory or in an external store, and the system must handle out-of-order arrivals, duplicates, and partial failures without stopping.
The simplest way to grasp the difference is to think about error recovery. In a batch system, if a job fails halfway, you fix the bug and rerun the entire batch. The input data is still there, unchanged. In a continuous system, if a processor crashes, you need to know exactly which events were processed, which were not, and whether any side effects (like database writes) need to be undone or compensated. That is a fundamentally harder problem.
Another lens is resource utilization. Batch jobs can be scheduled during off-peak hours and can use all available resources for a short burst. Continuous processing requires always-on capacity, even during low-traffic periods. The cost model flips: batch favors low, predictable resource usage with occasional spikes; continuous favors steady, moderate usage with the ability to scale up during traffic surges.
Neither is inherently better. The right choice depends on how much latency your domain tolerates, how expensive it is to reprocess data, and whether your operations team can handle the complexity of exactly-once semantics or idempotency.
The Mental Model Shift
Batch is a transaction mindset: you have a begin and end, and you can roll back. Continuous is a flow mindset: you cannot stop the river, so you build idempotent sinks and checkpointing. Most architectural mistakes come from applying the wrong mental model to the problem.
How It Works Under the Hood
Let us open the hood on both architectures, focusing on the mechanisms that cause the behavioral differences.
Batch: Scheduler, Executor, and Storage
A typical batch system has three components: a scheduler that decides when to run, an executor that runs the job logic, and a storage layer that holds input and output data. The scheduler can be a simple cron daemon or a sophisticated DAG orchestrator. The executor often runs in a container or VM that is provisioned for the job and torn down after. Storage is usually a distributed file system or object store.
The critical detail is that the scheduler does not care about the internal state of the job—it only cares about completion status. If the job fails, the scheduler can retry the entire unit from the beginning, because the input data is immutable and the output is either fully written or not written at all (if the job uses atomic writes). This simplicity is the superpower of batch: failure recovery is trivial, and the system can be built with minimal distributed consensus.
However, batch systems struggle with late-arriving data. If a record arrives after the batch window closes, it must wait for the next window or be handled by a separate reconciliation process. This creates a tension between latency (shorter windows) and completeness (longer windows).
Continuous: Stream Processor, State Store, and Checkpointing
A continuous architecture relies on a stream processing engine that consumes from a log or queue, maintains operator state, and periodically checkpoints its progress. The engine tracks an offset into the input stream, so on restart it can resume from the last committed offset. State is stored in a embedded key-value store (like RocksDB) or an external database.
The hard part is exactly-once semantics. To guarantee that each event is processed exactly once, the engine must coordinate between the input offset, the state store, and the output sink. This usually requires a distributed transaction or an idempotent sink. Many production systems settle for at-least-once and handle duplicates downstream.
Continuous systems excel at low latency and handling variable event rates, but they introduce complexity in state management. If the state grows large, checkpointing becomes expensive. If the processor crashes, recovery time depends on how much state must be rebuilt from the checkpoint.
Comparison Table
| Property | Batch | Continuous |
|---|---|---|
| Latency | Minutes to hours | Milliseconds to seconds |
| Failure recovery | Rerun the batch | Replay from checkpoint; handle duplicates |
| Resource usage | Spiky, can use spot instances | Steady, needs always-on capacity |
| State management | Stateless within a run; external DB | Stateful across events; checkpointed |
| Late data handling | Next window or separate pipeline | Watermarks and allowed lateness |
| Operational complexity | Low | High |
Worked Example: Order Fulfillment Pipeline
Consider an e-commerce system that processes orders from multiple warehouses. Orders arrive throughout the day, and the system must allocate inventory, calculate shipping costs, and trigger fulfillment. We will examine two designs: a batch pipeline that runs every hour, and a continuous pipeline that processes each order immediately.
Batch Design
Orders accumulate in a database table. Every hour, a job queries all orders with status 'pending', groups them by warehouse, and runs allocation logic. The job writes results to a fulfillment table and marks orders as 'processed'. If the job fails, it can be rerun because it only reads pending orders and writes with a transaction. The main drawback: an order placed at 9:59 AM waits until the 10:00 AM run, adding up to 59 minutes of latency. If the warehouse has limited inventory, early orders in the hour might lose stock to later orders if allocation is not first-come-first-served within the batch.
Continuous Design
Each order is published to a Kafka topic. A stream processor consumes the topic, looks up inventory in a Redis cache, and writes allocation decisions to a database. The processor maintains a state table of allocated quantities per warehouse to avoid overselling. Latency is under a second. However, if the processor crashes, it must replay the topic from the last checkpoint. During replay, inventory allocations might be duplicated unless the output sink is idempotent. The team must also handle out-of-order events if orders arrive late from a different source.
Which design wins? It depends on business constraints. If the SLA allows 60-minute latency, batch is simpler and cheaper. If the business needs real-time inventory visibility, continuous is necessary despite the complexity. A hybrid approach—micro-batch every 30 seconds—can offer a middle ground.
Key Takeaway
Map your latency tolerance and failure recovery cost before choosing. Do not let the allure of real-time drive you into a complex architecture you do not need.
Edge Cases and Exceptions
Every architecture has scenarios where the textbook answer breaks down. Here are the ones that trip up most teams.
Late-Arriving Data in Batch
Batch systems assume data arrives within the window. When a sensor report arrives three hours late due to network issues, it misses its window. Common fixes include a separate late-data pipeline or extending the window and accepting higher latency. Neither is clean. Late data often forces batch systems to adopt a lambda architecture (batch + speed layer), which doubles complexity.
State Explosion in Continuous
Continuous processors that maintain per-key state (e.g., user session data) can run into memory limits if the key space is large. The state store spills to disk, but checkpointing becomes slow. Teams often resort to windowed aggregations or external state stores, which reintroduce batch-like boundaries. The continuous system becomes a batch system in disguise.
Exactly-Once Is a Lie
True exactly-once semantics across multiple systems (stream processor, database, external API) is extraordinarily difficult. Most production systems settle for at-least-once and design downstream idempotency. If your workflow involves side effects like sending emails or charging credit cards, continuous processing requires careful compensation logic. Batch systems avoid this because the entire unit of work can be committed or rolled back.
Backpressure and Throttling
Continuous systems rely on backpressure to handle traffic spikes. If the downstream sink slows down, the stream processor must buffer or drop events. Batch systems naturally throttle because the job runs on a schedule and processes only what has accumulated. In a continuous system, a sudden spike can cause memory pressure and checkpoint failures, leading to data loss.
Limits of the Approach
No architecture is a silver bullet. Both batch and continuous have inherent limits that no amount of engineering can fully eliminate.
Batch Limits
Batch systems cannot provide real-time visibility. If your business requires sub-second decisions (fraud detection, live dashboards), batch is simply the wrong tool. Additionally, batch jobs have a startup overhead—spinning up containers, loading data, initializing connections—that makes very short windows inefficient. Below a certain window size (often 30–60 seconds), the overhead dominates the processing time, and the system behaves like a slow continuous system anyway.
Another limit is data freshness. A daily batch job means your reports are always at least 24 hours old. For operational decisions, that lag can be costly. Some teams mitigate this with incremental batch runs, but that adds complexity.
Continuous Limits
Continuous systems struggle with exactly-once semantics across heterogeneous sinks. If your workflow writes to a database, calls an API, and updates a cache, coordinating a transaction across all three is nearly impossible. The system will either duplicate or drop events during failures. Continuous systems also have a higher operational burden: monitoring lag, managing checkpointing, handling schema evolution in-flight.
Cost is another limit. Always-on clusters for continuous processing can be expensive, especially if the traffic is bursty. Auto-scaling helps but introduces latency during scale-up events. Batch systems can use spot instances and scale to zero between runs.
When Neither Fits
Some workflows require both low latency and strong transactional guarantees. In those cases, consider a hybrid: use continuous for the fast path and batch for reconciliation. This is the essence of the Kappa-plus architecture or a Lambda architecture with a unified stream layer. The complexity is real, but it may be the only way to satisfy conflicting requirements.
Reader FAQ
Can I use batch for real-time alerts?
Only if your alert latency tolerance is minutes or hours. For sub-second alerts, you need continuous processing. Some teams use micro-batch with very short windows (e.g., 5 seconds) but that is essentially continuous with a buffer.
Is continuous always more expensive?
Not always. If your traffic is steady and you need low latency, continuous can be cost-effective because you use resources efficiently. Batch can be cheaper if you can run on spot instances and tolerate spikes. The total cost depends on data volume, latency requirements, and operational overhead.
How do I handle late data in continuous systems?
Use watermarks and allowed lateness. Most stream processors let you define a window and a grace period for late events. Events that arrive after the grace period are dropped or sent to a dead-letter queue. You can also have a separate batch job to reconcile late data.
Should I start with batch and later migrate to continuous?
Often yes. Batch is simpler to build and debug. If your latency requirements are not strict, start with batch. If you later need lower latency, you can add a continuous layer for the hot path while keeping batch for historical processing. Migrating from continuous to batch is harder because you have to unwind stateful logic.
What about micro-batch?
Micro-batch (e.g., Spark Streaming) is a hybrid: it processes data in small batches (seconds) but uses the batch execution model. It offers a simpler programming model than true continuous while providing near-real-time latency. However, it inherits some batch overhead and may not achieve sub-second latency. It is a good compromise for many use cases.
Next steps: audit your current workflows. For each pipeline, write down the maximum acceptable latency and the cost of reprocessing. If latency is under 10 seconds and reprocessing is expensive, lean continuous. If latency can be minutes and reprocessing is cheap, lean batch. For everything else, consider micro-batch or a hybrid. The goal is not to pick a side, but to match the architecture to the workflow's natural rhythm.
Comments (0)
Please sign in to post a comment.
Don't have an account? Create one
No comments yet. Be the first to comment!