What this is for
spark-submit starts a Spark application on a cluster. You'll use it, or see it in a scheduler's logs, on most self-managed Spark platforms. This page covers the options you'll use on most days. Managed platforms such as Databricks set many of these for you.
The basic shape
spark-submit [options] app.py [arguments for your app]
Options go before the script. Anything after the script goes to your app, not to Spark. That's a common reason a setting appears to be ignored.
Options you'll use most
| Option | Meaning | Example |
|---|---|---|
--master | Where to run | local[4], yarn, k8s://https://host:6443 |
--deploy-mode | Where the driver runs | client or cluster |
--name | Name shown in the UI | --name daily-orders |
--driver-memory | Memory for the driver | 4g |
--executor-memory | Heap per executor | 8g |
--executor-cores | Cores per executor | 4 |
--num-executors | Executors (YARN) | 10 |
--conf | Any Spark setting | --conf spark.sql.shuffle.partitions=200 |
--py-files | Extra Python code | --py-files libs.zip |
--jars | Extra JAR files | --jars postgresql.jar |
--packages | JARs by Maven coordinate | --packages org.apache.kafka:kafka-clients:3.7.0 |
--files | Files sent to each executor | --files app.conf |
--queue | YARN queue | --queue etl |
Ready-to-use commands
Run on your own machine, using 4 cores:
spark-submit --master "local[4]" --driver-memory 4g app.py --date 2026-11-06
Run on YARN, for production:
spark-submit \
--master yarn \
--deploy-mode cluster \
--name daily-orders \
--queue etl \
--driver-memory 4g \
--executor-memory 8g \
--executor-cores 4 \
--num-executors 10 \
--conf spark.sql.shuffle.partitions=200 \
--py-files libs.zip \
app.py --date 2026-11-06
Run on Kubernetes:
spark-submit \
--master k8s://https://k8s-api.contoso.com:6443 \
--deploy-mode cluster \
--name daily-orders \
--conf spark.kubernetes.namespace=spark \
--conf spark.kubernetes.container.image=registry.contoso.com/spark-app:1.4 \
--conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \
--conf spark.executor.instances=5 \
local:///opt/app/app.py
local:// means the file is already inside the image.
Client mode or cluster mode?
client | cluster | |
|---|---|---|
| Driver runs on | The machine where you ran the command | A node in the cluster |
| Logs appear | In your terminal | In the cluster's logs |
| If your session ends | The job dies | The job keeps running |
| Good for | Development and debugging | Scheduled production jobs |
Simple sizing math
Start from the job's needs, then adjust using the Spark UI:
- Use 4-5 cores per executor. More often gives worse results.
- Leave some memory on each node for the OS and services.
- Remember the overhead: each executor uses its heap plus an overhead that's about 10% by default.
Example, with worker nodes of 16 cores and 64 GB:
Usable on a node: 15 cores, about 58 GB
Executors a node: 15 / 5 = 3
Per executor: 58 / 3 = about 19 GB total
Heap: 19 GB minus about 10% overhead = about 17 GB
So you'd set --executor-cores 5 --executor-memory 17g. Treat this as a starting point, not a final answer.
Let Spark scale the executor count when your cluster supports it:
--conf spark.dynamicAllocation.enabled=true \
--conf spark.dynamicAllocation.minExecutors=2 \
--conf spark.dynamicAllocation.maxExecutors=20 \
--conf spark.dynamicAllocation.shuffleTracking.enabled=true
Find the logs
# YARN: list applications, then fetch the logs
yarn application -list -appStates RUNNING,FAILED
yarn logs -applicationId application_1730000000000_0042 | less
# Stop a running app
yarn application -kill application_1730000000000_0042
# Kubernetes
kubectl get pods -n spark -l spark-role=driver
kubectl logs -n spark <driver-pod> --tail=200
For how to read the UI once a job runs, see the Spark UI guide.
First errors and what they mean
| Error | Usual cause | Fix |
|---|---|---|
ClassNotFoundException | A JAR is missing | Add it with --jars or --packages |
ModuleNotFoundError (Python) | Module isn't on the executors | Send it with --py-files, or install it in the image |
Container killed by YARN for exceeding memory limits | Off-heap use exceeded overhead | Raise spark.executor.memoryOverhead |
java.lang.OutOfMemoryError: Java heap space | Heap too small, or data skew | See the OOM guide |
App stays ACCEPTED | The YARN queue has no free capacity | Try another queue or wait; check the queue's limits |
Python in worker has different version | Driver and workers use different Pythons | Set PYSPARK_PYTHON to the same path |
Initial job has not accepted any resources | You asked for more than a node can supply | Lower executor memory or cores |
| Settings have no effect | Options were placed after the script | Move them before it |
Warning
Don't put passwords on the command line. They show up in process lists and the Spark UI's Environment tab. Read them from a secret store inside your app.
Check what Spark really used
The Environment tab in the Spark UI lists every setting the app ran with. Print them to the log too:
spark-submit --verbose --master "local[2]" app.py
Prevent it next time
- Keep a working command for each job in Git, not in someone's shell history.
- Set
--nameto something meaningful, so you can find the app later. - Change one setting at a time, and record the run time and result.
- Next read: shuffle partitions and AQE.