Spark Migrate CLI overview
Spark Migrate CLI is a command-line tool that helps migrate existing Apache Spark 2.x applications written in Scala, Java, or PySpark to Apache Spark 3.5.5.
The tool identifies compatibility issues, applies supported code and configuration changes, updates dependencies, and compiles and tests the migrated application.
This page explains the challenges involved in upgrading Spark applications, how Spark Migrate CLI addresses them, and the supported migration workflows.
Target versions
From | To | Status |
Spark 2.4.x, including Spark 2.3 and vendor-specific 2.x builds | Apache Spark 3.5.5 | Available |
The current migration target is Apache Spark 3.5.5 with Scala 2.12 and JDK 17.
The problem: A Spark upgrade is not just a version change
Upgrading from Spark 2.4.8 to Spark 3.5.5 involves more than updating the Spark version in a build file.
Spark 3 introduces changes to programming languages, JDK requirements, libraries, APIs, and runtime behavior. Some changes cause compilation or runtime failures, while others affect application results without generating errors.
These compatibility issues fall into six areas.
1. Platform compatibility
Spark 3.5 introduces changes to the underlying platform and its dependencies.
Component | Spark 2.4 | Spark 3.5 | Impact |
Scala | 2.11 | 2.12 or 2.13 | Scala versions are not binary compatible. Libraries and connectors built for Scala 2.11 must be replaced with compatible builds. |
JDK | 8 | 17 for this migration | Older build plugins and libraries may fail. Tests that initialize a local SparkSession may require additional JVM options such as --add-opens. |
Python | 2.7 or 3.x | 3.8+ | PySpark requires compatible Python, pandas, and PyArrow versions. NumPy 2 is not supported by this target. |
Logging | Log4j 1 | Log4j 2, starting with Spark 3.3 | Existing log4j.properties configurations may be ignored, affecting logging behavior. |
2. Code that no longer compiles
Spark 3 removes or changes several APIs supported in Spark 2.4.
Examples include:
- Accumulator v1 API (sc.accumulator).
- HiveContext and the SQLContext constructor.
- ProcessingTime.
- ShuffleWriteMetrics accessors.
- MLlib APIs such as KMeans.train(..., runs, ...) and the *WithSGD family.
- ExpressionEncoder.toRow.
- Koalas APIs, now available through pyspark.pandas.
These issues typically cause compilation failures or compatibility errors.
Spark Migrate CLI automatically rewrites APIs that have a supported Spark 3 equivalent. For issues that cannot be resolved automatically, the tool reports the affected source location and required action.
3. Code that compiles but fails at runtime
Some applications compile successfully but fail when processing data on Spark 3.5.
Common examples include:
- Datetime parsing: Spark 3 uses stricter date and timestamp parsing. Values accepted by Spark 2.4 may produce SparkUpgradeException. Certain date pattern characters, including Y, w, u, and E, may also cause errors.
- Table writes: Spark 3 may reject incompatible values during table writes where Spark 2.4 previously produced null values.
- Historical dates: Reading or writing older dates in Parquet and Avro may cause compatibility errors. Applications using sentinel dates such as 0001-01-01 require additional attention.
- Self-joins: References to columns in self-joins may fail because Spark 3 detects ambiguous column references that Spark 2.4 previously accepted.
4. Code that runs but produces different results
Some Spark 3 behavior changes do not cause compilation or runtime errors. Applications may complete successfully while producing different results.
Examples include:
Spark 2.4 behavior | Spark 3.5 behavior |
add_months('2019-02-28', 1) returns 2019-03-31, preserving month-end behavior. | Returns 2019-03-28. |
CAST(' 316 ' AS INT) returns null. | Returns 316 because padded strings are accepted. |
ts > '2020-01-01' retains certain midnight rows. | The string is converted to a timestamp, changing comparison results. |
Row(name=..., age=...) sorts fields by name. | Preserves the order in which fields are specified. |
groupByKey(...).count() names the key column value. | Names the key column key. |
from pyspark.sql.functions import * imports the existing function set. | Also imports mode, which may conflict with an existing variable. |
pandas-on-Spark drop("col") removes a column. | Starting with Spark 3.3, it may interpret the argument as an index label instead. |
These differences may remain undetected unless tests explicitly verify the affected values.
5. Dependencies and connectors
Libraries and connectors that depend on Spark may require new versions when migrating to Spark 3.5.
For example:
- Delta Lake 0.6 requires migration to a compatible delta-spark 3.x version and additional session configurations.
- spark-xml and spark-avro require compatible Spark 3 artifacts.
- hadoop-aws dependencies may need to move from Hadoop 2.7 to Hadoop 3.3.
- Older Jackson and Guava versions may conflict with the libraries included in Spark 3.5.
Spark dependencies must also be configured correctly. Including Spark dependencies in the application JAR instead of marking them as provided may cause classpath conflicts.
6. Build configurations and launch scripts
Spark migrations may also require changes to build tools and application launch configurations.
Examples include:
- spark-submit scripts referencing packages built for Scala 2.11.
- SPARK_HOME pointing to a Spark 2 installation.
- Launch commands using the removed yarn-client master URL.
- Scripts invoking vendor-specific commands such as spark2-submit.
- Older sbt and Maven plugins that are incompatible with JDK 17.
Why Spark migrations are challenging
Spark migration issues can be difficult to identify and resolve for several reasons:
- Issues occur across multiple files. Compatibility problems may exist in application code, embedded SQL, standalone SQL files, build configurations, dependency definitions, and launch scripts.
- Some changes are difficult to detect. Applications may run successfully but produce different results because of changes in Spark behavior.
- Legacy configurations require careful selection. Enabling unnecessary spark.sql.legacy.* settings can preserve outdated behavior and make future cleanup difficult.
- Migration requires repeated effort. Organizations with multiple Spark applications must identify and resolve similar compatibility issues across repositories.
What Spark Migrate CLI does for you
Spark Migrate CLI automates supported migration tasks and identifies issues that require manual intervention.
Area | What Spark Migrate CLI does |
Platform | Updates builds to Scala 2.12 and JDK 17, upgrades supported build dependencies and plugins, adds required test JVM options, and checks Python compatibility. |
Removed APIs | Rewrites APIs with supported Spark 3.5 equivalents and reports unsupported changes. |
Runtime failures | Adds compatibility configurations where required to restore Spark 2.4 behavior. |
Behavior changes | Rewrites supported code to preserve existing results or reports issues requiring manual resolution. |
Dependencies | Updates supported connectors and Spark-related libraries, adds required configurations, and marks Spark dependencies as provided. |
Launch scripts | Updates supported spark-submit scripts, package references, environment settings, and master URLs. |
The tool uses 145 documented migration rules, each identified by a SPARK-MIG code.
Each rule explains:
- What changed and the Spark version in which the change occurred.
- When the rule applies.
- What the tool changes automatically.
- Whether manual intervention is required.
Every identified issue has one of three outcomes:
- Rewritten: The tool automatically modifies the affected code.
- Restored: The tool adds a compatibility configuration to preserve existing behavior.
- Reported: The tool identifies the issue and recommends a resolution when an automatic change is not safe.
What you get
Spark Migrate CLI provides the following outputs:
- Analysis report: Identifies compatibility issues, affected source locations, and required actions before code generation.
- Reviewable changes: Generates changes to application code, build files, dependencies, configurations, and supported launch scripts.
- Build and test results: Compiles the migrated application and runs its existing tests against Spark 3.5.5.
- Change explanations: Associates each code change and configuration with the migration rule that required it.
- Data validation: Compares the original and migrated application outputs to identify differences.
- Git integration: Applies changes to a new Git branch for review without modifying the original repository until requested.
The analysis report
Spark Migrate CLI generates an HTML analysis report before modifying application code.
The report provides an overall migration verdict and lists compatibility issues, affected source locations, and recommended actions.
Migration verdicts
Verdict | Description |
Migratable automatically | No manual changes are required before code generation. |
Migratable, with compile fixes | Some issues may require manual changes during compilation. |
N things to fix before migrating | Mandatory issues must be resolved before the migration can continue. |
Blocked | An unsupported dependency or library prevents migration until it is replaced or removed. |
Finding categories
The analysis report groups findings into the following categories:
Category | Description |
Must fix | Issues that may cause failures or change application results and cannot be resolved automatically. The run command stops when these issues are identified. |
Compile fix | Issues that prevent compilation and require code changes. |
Watch for | Potential behavior differences that may occur with specific input data. |
Done for you | Issues resolved through automated code changes or compatibility configurations. |
FYI | Informational findings that typically do not affect application behavior. |
Each finding includes:
- The migration rule and a link to its documentation.
- An explanation of the Spark compatibility change.
- The required action, if any.
- The affected source file, line number, and proposed modification.
You can search and filter the report and attach it to a ticket or pull request.
What it saves
The following table summarizes the migration results from the example applications.
Application | Manual intervention | Migration time |
Scala with sbt | None | Approximately 75 seconds |
Java with Maven | Add generated configurations to the external scheduler's launch command. | — |
PySpark | Resolve one column alias, rename one variable, and configure an environment variable for local tests. | — |
In these examples, Spark Migrate CLI handled the remaining supported migration tasks, including:
- Dependency and connector upgrades.
- spark-submit script updates.
- Legacy compatibility configurations.
- Supported MLlib and Koalas API changes.
- Compilation and unit testing.
Actual migration time depends on the repository, dependencies, and build and test duration.
How it works
Spark Migrate CLI processes each migration as a job.
Each job represents one repository and is stored in a dedicated directory:
./spark-migrate-jobs/<job-id>/
1. Analyze
The analyze command creates a copy of the source repository and uses the appropriate analysis engines.
Language | Analysis engine |
Scala | Scalafix, using compiled repository information for type-aware analysis. |
Java | OpenRewrite, using the repository's classpath. |
PySpark | PySparkler and Acceldata Python migration rules. |
SQL | sqlfluff with 17 Spark SQL rules for embedded and standalone SQL. |
The tool generates the analysis report containing compatibility findings and recommended actions.
2. Generate code changes
The codegen command creates a separate working copy and:
- Rewrites supported code to preserve Spark 2.4 behavior.
- Adds compatibility configurations where required.
- Updates the build to Spark 3.5.5, Scala 2.12.18, and JDK 17, where applicable.
3. Compile and test
The tool compiles the migrated application and runs the repository's existing tests.
Compilation or test failures are reported for investigation and resolution.
4. Validate
The validate command compares the outputs of the original Spark 2.x application and the migrated Spark 3.5.5 application.
Validation checks include:
- Schema comparison.
- Row counts.
- Row-level differences based on key columns.
- Aggregate values.
By default, failed validation prevents the migration changes from being applied.
5. Apply
The apply command applies the generated changes to the repository on a new Git branch without committing them.
Alternatively, the migrate command processes a remote Git repository, commits the migration changes to a new branch, and optionally pushes the branch.
Note
The run command automates analysis, code generation, compilation, and testing. It stops when manual intervention is required. Data validation and applying changes are separate operations.
What it supports
Spark Migrate CLI supports the following languages and build systems.
Application type | Code migration | Build and dependency updates | Compile and test |
Scala with sbt | Supported | Supported | sbt test |
Scala with Maven | Supported | Supported | mvn test |
Java with Maven | Supported | Supported | mvn test |
PySpark | Supported | requirements.txt, setup.py, pyproject.toml, Pipfile, and conda configurations | pytest |
SQL | Embedded SQL is analyzed; .sql and .hql files are checked but not modified. | Not applicable | Through the host language |
Supported source and target versions
Component | Source version | Target version |
Apache Spark | 2.4.x, including Spark 2.3 and vendor-specific 2.x builds | Apache Spark 3.5.5 |
Scala | 2.11 | 2.12.18 |
JDK | 8 | 17 |
Python (PySpark) | Existing repository version | 3.8–3.11 |
Multi-module sbt and Maven builds are supported. Each migration job processes one repository.

Have a suggestion?