Opening scenario

Your team is building a fraud-detection stream processor in Flink. The PM asks: "alert me when a single account has more than 5 transactions totaling $10,000 in a 1-minute period." Simple ask. You start writing:

SELECT account_id, COUNT(*), SUM(amount)
FROM transactions
GROUP BY account_id
HAVING COUNT(*) > 5 AND SUM(amount) > 10000

But the data is an infinite stream — GROUP BY over the entire input never produces a final result. Flink keeps updating each account's all-time count and sum, because it never knows when the group is done. You need to bound the aggregation in time. The PM said "1-minute period" — but is that "the last 60 seconds of wall-clock time," "a fixed 12:00:00–12:00:59 bucket," "60 seconds starting from when the account became active," or "60 seconds rolling, recomputed every 10 seconds"? Each of these is a different operator with different semantics, different state cost, different latency. The first decision in any stateful streaming query is which kind of window to use, and that decision is mostly irreversible once the pipeline is in production.

In the full tutorial

  • What's the problem windows actually solve?
  • What are the canonical window types and what does each give up?
  • Why does "which time" affect the window's correctness?
  • What does state look like for a windowed aggregation, and why does this matter for scale?
  • When does a window emit, and how do triggers and watermarks interact?
  • Sample Flink SQL window queries
  • Closing: When to reach for this

Glossary history

Click dotted jargon to save explanations here.