Firebolt and Apache Druid are both sold as sub-second dashboards. One of them scales compute to zero when you stop the engine. The other does not.
Firebolt is a cloud warehouse: tablets in object storage, a sparse primary index per tablet, optional aggregating indexes, isolated engines billed in FBUs. Standard US compute is $0.23 per FBU-hour. A compute-optimized Small is 4 FBU, $0.92/hour while the engine runs, per-second billing (Firebolt billing). An idle engine you forgot to stop is a warehouse you left on.
Druid is a streaming OLAP database: Kafka supervisors, realtime tasks, immutable segments, Historicals, Brokers. The dashboard hits local bitmaps. The cluster does not go away when the workbook closes.
Firebolt documents DATE_TRUNC:
SELECT
DATE_TRUNC('minute', ts) AS minute,
country,
COUNT(*) AS events,
SUM(revenue) AS revenue
FROM page_views
WHERE ts >= NOW() - INTERVAL '1 hour'
GROUP BY 1, 2
In Firebolt that is an engine scan pruned by PRIMARY INDEX (country, ts), or served from an aggregating index whose grouping keys match. In Druid that is scatter/gather over segments that may already be rolled up at ingest.
ClickHouse® vs Firebolt is the engine comparison. ClickHouse vs Druid is the process graph. This page is what you pay when nobody is looking, and whether Kafka ingest looks like a supervisor or like INSERT.
CREATE STREAM is not a supervisor
Druid pulls the topic. Realtime tasks answer during the in-flight interval. maxRowsPerSegment defaults to 5,000,000 post-aggregation rows. Kafka handoffConditionTimeout defaults to 15 minutes (Druid supervisor). Handoff publishes to deep storage. Historicals load. Freshness is seconds if the supervisor is healthy. There is no "stop the Historicals overnight."
Firebolt writes tablets, then queries with an engine. COPY from object storage still applies. Kafka is documented as CREATE STREAM plus INSERT INTO … SELECT FROM READ_STREAM(...). Offsets advance in that write transaction (CREATE STREAM, READ_STREAM):
CREATE LOCATION kafka_src WITH (SOURCE = KAFKA, BROKERS = 'broker:9092');
CREATE STREAM page_views_stream (
ts TIMESTAMP,
country TEXT,
revenue DOUBLE
)
TOPIC = 'page_views'
LOCATION = 'kafka_src'
TYPE = 'JSON';
INSERT INTO page_views
SELECT ts, country, revenue
FROM READ_STREAM(STREAM page_views_stream);
No realtime task. No segment handoff. No Historicals. The engine must be running for the INSERT. That is warehouse-shaped ingest: a SQL write on billed compute, not scatter/gather over in-flight segments.
Add the cube after the table exists
Firebolt's primary index is a sparse sort, one key sample per granule (default 8,192 rows), not a uniqueness constraint. Filters that match the leading columns prune granules by binary search inside each tablet. Same idea as a MergeTree ORDER BY, with tablet metadata on top.
An aggregating index is a precomputed GROUP BY stored as partial aggregate state. Firebolt maintains it in the same transaction as the base write. You query the base table. The planner rewrites to the index when grouping keys match. Get the grouping order wrong and you scan the fact table anyway.
CREATE AGGREGATING INDEX page_views_1m ON page_views (
DATE_TRUNC('minute', ts),
country,
COUNT(*),
SUM(revenue)
);
Druid ingest rollup is the same economic idea with a harder contract. Dimensions and metrics are declared in the supervisor spec. Change country to campaign and you reindex. Bitmaps sit on every dimension. High-cardinality IDs as dimensions are how segments explode.
Firebolt lets you add the aggregating index after the table exists. Druid wants the cube at ingest if you want the cheap segment. Query-time SQL over raw events is ClickHouse or a warehouse scan, not classic Druid.
Isolation you buy with FBU
You can run isolated engines so concurrency in workbook A does not steal CPU from workbook B. That is a usage pattern, not a product rule that one workbook equals one engine. FBU = node FBU × nodes × clusters (engine consumption).
A Medium compute-optimized engine is 8 FBU, $1.84/hour on Standard US. Two of those left on 12 hours/day, 22 days is 2 × $1.84 × 12 × 22 ≈ $973/month compute before storage (arithmetic, not a quote). Storage is pass-through S3. us-east-1 is $27.07 per TiB/month on Firebolt's billing table.
Auto-stop helps if resume is acceptable. A 15-second customer tile cannot auto-stop. Then you are paying FBU hours the way you pay a warehouse that never sleeps. A compute-optimized Small left up 12 hours × 22 days is $0.92 × 12 × 22 ≈ $243/month for that engine. Storage-optimized Small is a different node (8 FBU, $1.84/hour Standard US). Do not mix the two.
Druid isolation is segment placement. Historicals serve many datasources. A noisy dashboard is another Broker query on the same Historicals unless you split clusters. You pay the process graph whether anyone is looking. The marginal cost of another 15-second refresh is ~0 once segments are local. That is why Druid wins high-QPS closed cubes, and why the cluster never looks cheap on a quiet Sunday.
Apache Druid alternatives is people looking at Coordinators, Overlords, MiddleManagers, Historicals, Brokers, ZK. Firebolt's people cost is index design plus whoever owns COPY / READ_STREAM cadence. An aggregating index that does not match the GROUP BY is a silent full scan. Primary index column order is the same trap as a bad MergeTree ORDER BY.
Kafka ingest without leaving an engine on
Neither an engine nor a Broker is an HTTP contract. Tinybird publishes ClickHouse SQL as a pipe. Kafka ingest is a connector, not READ_STREAM on billed FBU. HTTP ingest is the Events API (documented default: 100 requests/sec per datasource).
The aggregating index analog is a materialized pipe into AggregatingMergeTree. You declare it in git. The engine is not sitting on waiting for INSERT:
DESCRIPTION >
Minute-country rollup. States, not finished counts.
NODE minute_country
SQL >
SELECT
toStartOfMinute(ts) AS minute,
country,
countState() AS events,
sumState(revenue) AS revenue
FROM page_views
GROUP BY minute, country
TYPE MATERIALIZED
DATASOURCE page_views_1m
Target datasource holds the states. The endpoint reads merges:
DESCRIPTION >
Last hour from the rollup, not from the raw fact table.
SCHEMA >
`minute` DateTime,
`country` LowCardinality(String),
`events` AggregateFunction(count, UInt64),
`revenue` AggregateFunction(sum, Float64)
ENGINE "AggregatingMergeTree"
ENGINE_SORTING_KEY "country, minute"
DESCRIPTION >
Serve the rollup.
NODE from_rollup
SQL >
SELECT
minute,
country,
countMerge(events) AS events,
sumMerge(revenue) AS revenue
FROM page_views_1m
WHERE minute >= now() - INTERVAL 1 HOUR
GROUP BY minute, country
ORDER BY minute, country
TYPE ENDPOINT
npx tinybird preview / npx tinybird deploy. The 15-second tile is compute on that rollup, not an engine left on and not a Broker pool. Developer plans and vCPU overage at $0.0002 per vCPU-second are on Tinybird pricing.
You do not get Firebolt's isolated engines for BI concurrency, or Druid's ingest-time bitmaps. Wrong buy for a BI team that already lives in Firebolt workbooks. Wrong buy for a Druid CoE with a frozen cube. Right buy when ingest is Kafka or HTTP, the GROUP BY will change, and the consumer is an app.
If you need in-flight segments, you still need Druid
Use Firebolt when tablets will be loaded, the primary index will be designed, and BI concurrency needs isolated engines. Use Druid when Kafka must be queryable in seconds on a closed cube and a team already runs supervisors. Use Tinybird when those same events have to be an API.
Frequently Asked Questions (FAQs)
Does Firebolt replace a Druid supervisor?
No. Supervisors, realtime tasks, and handoff are a streaming indexer. READ_STREAM is a SQL write into tablets on a running engine. Aggregating indexes are a warehouse rollup maintained on that write. Different process, similar SQL shape.
Can Firebolt ingest Kafka at all?
Yes. CREATE STREAM plus INSERT INTO … SELECT FROM READ_STREAM(...). Offsets commit with the write. That is not in-flight segments and Broker scatter/gather. If the engine is stopped, the INSERT does not run.
