Spark Partitions and File Sizes: repartition, coalesce and the Small-Files Problem
How in-memory partitions become output files, when to repartition or coalesce, and how to stop a job from writing ten thousand tiny files.
Apache SparkIntermediate2 min readUpdated 11 Oct 2026
Two different "partitions"
- In-memory partitions: chunks of a DataFrame that tasks process in parallel. One task per partition per stage.
- Storage partitions: directories on disk, like
sales/order_date=2026-10-01/, created bypartitionBy.
Each in-memory partition writes at least one file per storage partition it contains. That is where the small-files problem comes from.
repartition vs coalesce
repartition(n) / repartition(col) | coalesce(n) | |
|---|---|---|
| Shuffle | Yes, full shuffle | No, merges existing partitions |
| Can increase partitions | Yes | No |
| Balanced output | Yes | Can be skewed |
| Use for | Spreading work, clustering by a column before write | Cheaply reducing the number of output files |
# 200 shuffle partitions × 30 dates could write up to 6,000 files
df.write.partitionBy("order_date").parquet(path)
# cluster rows by the storage partition first: roughly one file per date
(df.repartition("order_date")
.write.partitionBy("order_date")
.parquet(path))Why small files hurt
- Every file means metadata to list and open; query planning slows down.
- Columnar formats compress and skip data poorly in tiny files.
- Object stores add per-request latency and cost.
A common target is files of roughly 128 MB to 1 GB each.
Tools that help
- Adaptive Query Execution (
spark.sql.adaptive.enabled, on by default in Spark 3.2+) coalesces small shuffle partitions automatically. spark.sql.files.maxRecordsPerFilecaps rows per file to avoid giant files.- Table formats: Delta Lake
OPTIMIZE(and Iceberg/Hudi equivalents) compact small files after the fact.
A quick checklist
- Choose storage partition columns with modest cardinality (dates, not user IDs).
- Repartition by those columns before writing.
- Let AQE size shuffle partitions; tune
spark.sql.shuffle.partitionsonly when needed. - Compact regularly if many small batches append to the same table.
Finished this note?
