spark-best-practices
Skill1 starsChanged 3 months agoApache-2.0View on GitHub
General Apache Spark best practices for scalable, maintainable DataFrame jobs: avoid driver materialization, reduce shuffle, join efficiently, and cache carefully. Use when optimizing Spark performance, reviewing PySpark jobs, or writing new DataFrame pipelines.
2 other projects use a version of this.
Adopted by
Most recently taken up by
- baekenough/oh-my-customcodetheir own version, first seen Oct 3, 2026
- BigDataBoutique/skillstheir own version, first seen Mar 5, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- baekenough/oh-my-customcode★ 42same name
- BigDataBoutique/skills★ 2same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository6 other files it gives its agents.
- lake-catalogSkill
- lake-querySkill
- polars-submitSkill
- spark-lake-catalogSkill
- spark-lineageSkill
- spark-submitSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
13 rules. About 0 are common, 8 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈8
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 12
Use this skill for general Apache Spark guidance when optimizing performance, reliability, and maintainability.
- Very specific: line 16
Avoid collect(), toPandas(), and large take() in core data paths.
- Distinctive: line 18
Keep heavy transformation and write paths in Spark DataFrame execution.
- Distinctive: line 22
Use Spark SQL/DataFrame functions so Catalyst can optimize execution plans.
- Distinctive: line 23
Avoid row-by-row Python logic when equivalent DataFrame expressions exist.
- Distinctive: line 24
Keep transformations declarative and composable.
- Very specific: line 30
Use coalesce when reducing output partitions.
- Distinctive: line 43
Consider checkpointing for very long lineage plans.
- Very specific: line 47
Prefer columnar formats (Parquet/Delta/Iceberg) when possible.
- Distinctive: line 49
Avoid small file explosion.
- Very specific: line 59
Use explain() and execution metrics/logs to inspect physical plans and shuffle boundaries.
- Distinctive: line 65
Every Structured Streaming query needs a stable checkpoint location.
- Very specific: line 69
Use shared storage for cluster runs, not local /tmp, because executors must be able to see the same checkpoint path.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Spark Best Practices
Use this skill for general Apache Spark guidance when optimizing performance, reliability, and maintainability.
1) Keep execution distributed
- Avoid
collect(),toPandas(), and largetake()in core data paths. - Materialize to driver memory only for very small control outputs (metrics, IDs, summaries).
- Keep heavy transformation and write paths in Spark DataFrame execution.
2) Prefer DataFrame APIs to Python loops
- Use Spark SQL/DataFrame functions so Catalyst can optimize execution plans.
- Avoid row-by-row Python logic when equivalent DataFrame expressions exist.
- Keep transformations declarative and composable.
3) Reduce shuffle cost
- Project and filter early to reduce data volume before joins/aggregations.
- Repartition intentionally before heavy joins/writes.
- Use
coalescewhen reducing output partitions. - Watch for skewed keys and apply skew mitigation.
4) Use efficient joins
- Broadcast small dimension tables when appropriate.
- Align join key types and null handling before joins.
- Validate expected join cardinality to avoid explosive outputs.
5) Cache only reused intermediates
- Cache/persist DataFrames only when reused across multiple downstream actions.
- Unpersist promptly when no longer needed.
- Consider checkpointing for very long lineage plans.
6) Write in table-friendly layouts
- Prefer columnar formats (Parquet/Delta/Iceberg) when possible.
- Partition by bounded-cardinality business keys.
- Avoid small file explosion; compact files when needed.
7) Be explicit with schema and quality
- Define schemas explicitly where practical.
- Normalize data types across sources before joins/unions.
- Handle null semantics intentionally in filters, joins, and aggregations.
8) Observe and verify
- Use
explain()and execution metrics/logs to inspect physical plans and shuffle boundaries. - Track row counts and key metrics at major steps.
- Compare runtime and output quality after each optimization pass.
9) Set Structured Streaming checkpoints
Every Structured Streaming query needs a stable checkpoint location. The checkpoint stores progress metadata and, for stateful queries such as windows, state-store data that Spark needs to recover correctly.
Use shared storage for cluster runs, not local /tmp, because executors must be
able to see the same checkpoint path.
oleander provides spark.oleander.app.state.dir as a shared application state
directory that users can use for streaming checkpoints.
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, count, window
spark = SparkSession.builder.appName("message-counts").getOrCreate()
state_dir = spark.conf.get("spark.oleander.app.state.dir", "").strip()
checkpoint = f"{state_dir.rstrip('/')}/public-stream/checkpoints/message-counts"
events = (
spark.readStream.format("kafka")
.option("kafka.bootstrap.servers", "localhost:9092")
.option("subscribe", "messages")
.load()
)
counts = (
events.selectExpr("CAST(value AS STRING) AS body", "timestamp AS event_time")
.withWatermark("event_time", "1 minute")
.groupBy(window(col("event_time"), "1 minute"))
.agg(count("*").alias("message_count"))
)
query = (
counts.writeStream
.format("console")
.outputMode("append")
.option("checkpointLocation", checkpoint)
.start()
)
query.awaitTermination()Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

