Skip to main content
ArcPy Migration

The Migration Playbook

A dated file-by-file strategy for mapping ArcPy functions, identifying gaps, and validating old and new implementations in parallel.

PUBLISHEDFEB 2026
SERIESARCPY MIGRATION
PART2 OF 3
Sumi-e ink painting representing the transition from legacy ArcPy scripts to modern open-source geospatial tools
  • Migration scope depends on the script, data, dependencies, target runtime, and review requirements
  • Some ArcPy capabilities need workarounds, retained software, or a different design
  • A hybrid approach may retain ArcPy for specialist work while other workflows move to open tools
  • Parallel testing, failure capture, and human review are required before a production decision

Part 1 records the business-case framework for migration. This part turns that decision into a bounded implementation plan.

This post is the actual playbook: how to inventory your scripts, which functions map to what, which functions have no direct open-source equivalent (and what to do about them), and how to run old and new in parallel until the evidence is sufficient.

Most migration guides say "use GeoPandas instead of ArcPy" and leave it there. That's not enough. You need to know which ArcPy functions translate cleanly, which require workarounds, and which mean you should keep ArcPy for those specific workflows. For a detailed function-by-function translation, see our ArcPy to GeoPandas guide.

The Inventory-First Approach

Before migrating anything, inventory everything. The duration depends on the estate. The purpose is to find scripts that should be deleted, retained, or migrated before a delivery plan is approved.

Step 1: Find All ArcPy Scripts

Start with a simple recursive search across your scripts directory for any Python file that contains an import arcpy statement. This gives you a definitive list of every file that depends on ArcPy, along with a total count. Initial counts are often incomplete because scripts live in project folders, shared drives, and archived directories. Record the search scope and confirm the inventory with the owners.

Step 2: Categorise Each Script

CategoryDefinitionAction
Green (easy)Standard geoprocessing (Buffer, Intersect, Dissolve, Join)Migrate to GeoPandas
Yellow (medium)Uses arcpy.env settings, cursor operations, or field calculationsMigrate with refactoring
Red (hard)Network Analyst, Spatial Analyst, 3D Analyst, or Enterprise integrationKeep in ArcPy or find workarounds
xGrey (obsolete)No longer used, duplicate, or supersededDelete

ILLUSTRATIVE INVENTORY DISTRIBUTION

The original distribution is an illustration, not a benchmark. Classify the actual inventory as easy, review-needed, specialist, or obsolete. The obsolete group may reduce maintenance scope, but deletion still needs owner confirmation and recovery controls.

Function Mapping Table

This is the reference table your team will use daily during migration. For each ArcPy function, the open-source equivalent and any caveats. See our side-by-side benchmark comparison for performance data on these equivalents.

Function mapping reference chart for ArcPy to open-source migration showing equivalent libraries
ArcPy FunctionOpen-Source EquivalentNotes
arcpy.analysis.Buffergdf.buffer(distance)GeoPandas. Ensure projected CRS for metre units
arcpy.analysis.Intersectgpd.overlay(gdf1, gdf2, how='intersection')GeoPandas overlay
arcpy.analysis.Uniongpd.overlay(gdf1, gdf2, how='union')GeoPandas overlay
arcpy.analysis.SpatialJoingpd.sjoin(gdf1, gdf2, how='inner')GeoPandas spatial join
arcpy.management.Dissolvegdf.dissolve(by='column')GeoPandas dissolve
arcpy.management.Mergepd.concat([gdf1, gdf2])pandas concat
arcpy.management.Clipgpd.clip(gdf, mask)GeoPandas clip
arcpy.management.Projectgdf.to_crs(epsg=4326)GeoPandas CRS transformation
arcpy.management.AddFieldgdf['new_col'] = valuepandas column assignment
arcpy.management.CalculateFieldgdf['col'] = gdf['col'].apply(func)pandas apply
arcpy.management.SelectByAttributegdf[gdf['col'] == value]pandas filtering
arcpy.management.SelectByLocationgdf[gdf.intersects(geometry)]GeoPandas spatial filtering
arcpy.conversion.FeatureClassToFCgdf.to_file('output.gpkg')Fiona via GeoPandas
arcpy.conversion.TableToTabledf.to_csv('output.csv')pandas export
arcpy.da.SearchCursorfor idx, row in gdf.iterrows()pandas iteration (or vectorised)
arcpy.da.UpdateCursorgdf.loc[condition, 'col'] = valuepandas vectorised update
arcpy.da.InsertCursorgdf = pd.concat([gdf, new_rows])pandas concat
arcpy.Describegdf.crs, gdf.total_bounds, gdf.dtypesGeoPandas properties
arcpy.ListFeatureClassesglob.glob('*.gpkg')Python glob
arcpy.sa.Rasterrasterio.open('file.tif')rasterio
arcpy.sa.ZonalStatisticsAsTablerasterstats.zonal_stats()rasterstats package
arcpy.sa.ExtractByMaskrasterio.mask.mask()rasterio.mask
arcpy.sa.Sloperichdem.TerrainAttribute(dem, 'slope')richdem or custom numpy
arcpy.sa.Aspectrichdem.TerrainAttribute(dem, 'aspect')richdem

This table is a starting reference. Verify every proposed equivalent against the target data, runtime, licence, output contract, and validation method.

Gaps Without a Direct Equivalent

Some ArcPy functions have no clean direct open-source replacement. Identify those boundaries before committing to a timeline, and record whether the workflow should stay on ArcPy, use a partial alternative, or require a new design.

ArcPy FunctionWhy No EquivalentWorkaround
arcpy.na.MakeServiceAreaLayerNetwork Analyst is proprietarypgRouting (PostGIS) or OSRM
arcpy.na.MakeClosestFacilityLayerNetwork AnalystpgRouting or NetworkX
arcpy.na.MakeODCostMatrixLayerNetwork AnalystpgRouting or OSRM API
arcpy.un.TraceProprietary data modelNo equivalent - keep ArcPy
arcpy.management.CreateTopologyArcGIS topology rulesPostGIS topology (partial)
arcpy.management.ValidateTopologyArcGIS topology validationPostGIS ST_IsValid + custom rules
arcpy.cartography.SimplifyLineCartographic generalisationShapely simplify (less sophisticated)
arcpy.cartography.CollapseHydroPolyCartographic specialisationNo equivalent
arcpy.ia.ClassifyRasterImage Analyst extensionscikit-learn + rasterio (more code)
arcpy.ddd.ViewShed3D Analyst extensionGRASS GIS r.viewshed (command-line)
arcpy.ddd.SurfaceVolume3D Analyst extensionCustom numpy calculation
arcpy.management.MakeQueryLayerArcGIS Enterprise integrationDirect SQL via SQLAlchemy

The Assessment

Of these 12, only Utility Network tracing has genuinely no workaround. The rest have alternatives that require more code but are functional. The question is whether the extra development effort is worth the licence savings. For Network Analyst functions, pgRouting is a capable alternative but requires PostGIS setup and a different data model - budget 2-3 weeks for the learning curve.

File-by-File Strategy

Each script gets migrated individually, not as a batch. This is the step-by-step process for a single script. Repeat for each Green, then Yellow.

1

Read the script

Understand what it does, not just what functions it calls. Talk to the analyst who runs it

2

Map the functions

Use the mapping table above to identify equivalents for every ArcPy call

3

Check for gaps

Any Red functions? If so, decide: workaround, keep in ArcPy, or redesign the workflow

4

Rewrite from scratch

Use GeoPandas/rasterio idioms. Do not transliterate ArcPy line-by-line - idiomatic open-source code is vectorised, not row-by-row

5

Test with the same data

Run old (ArcPy) and new (GeoPandas) on identical input datasets

6

Compare outputs

Geometry count, attribute values, CRS, spatial extent. Use the comparison script below

7

Document differences

Some differences are expected: floating-point precision (1e-6), sort order, field name casing

8

Validate with the analyst

The person who runs this workflow must confirm the output is correct. Technical equivalence is not enough - business equivalence matters

DO NOT TRANSLITERATE

The biggest migration mistake is converting ArcPy line-by-line into GeoPandas. ArcPy uses cursor-based, row-by-row processing. GeoPandas is vectorised. A transliterated script will be slower than both the original ArcPy and idiomatic GeoPandas. Rewrite from scratch using GeoPandas patterns.

Parallel Testing

Never switch over without running old and new in parallel. Automate the validation rather than comparing outputs by eye - human spot-checks miss edge cases.

A well-structured comparison function reads both the ArcPy output and the GeoPandas output as GeoDataFrames, then runs four checks: row count equality, CRS match, column set equality, and spatial extent agreement within a configurable tolerance (typically 1mm for projected coordinate systems). Any failed check prints a clear diagnostic. Run this function as part of your CI pipeline so failures are caught immediately, not during analyst review a week later.

Minimum 2 Weeks Parallel

Run both old (ArcPy) and new (GeoPandas) scripts on the same data for at least 2 weeks. Compare every output. Only switch over when you've had zero discrepancies for 2 consecutive weeks. This catches edge cases that unit tests miss - unusual geometries, encoding issues, projection edge cases.

Common Migration Patterns

Several patterns recur in migration work. Each shows the ArcPy original and the idiomatic GeoPandas replacement; confirm the fit against your inventory.

Pattern 1: arcpy.env.workspace to working directory

ARCPY

ArcPy scripts typically open by setting arcpy.env.workspace to a file geodatabase path and enabling overwriteOutput. These two global settings implicitly govern every subsequent geoprocessing call in the script, creating hidden state that can cause unexpected behaviour when scripts are called from automated pipelines.

GEOPANDAS

Replace with a plain Python path constant - typically a string or pathlib.Path variable set at the top of the script. No equivalent of overwriteOutput is needed: GeoPandas writes to whatever path you specify and overwrites by default. Explicit beats implicit.

Pattern 2: Cursors to pandas operations

ARCPY (ROW-BY-ROW)

The ArcPy pattern opens an UpdateCursor as a context manager, iterates through every row in a feature class, checks a field value, conditionally updates another field, and commits the change row by row. For a 100,000-record parcel dataset, this means 100,000 individual write operations. The overhead is substantial.

GEOPANDAS (VECTORISED)

The GeoPandas equivalent uses a boolean mask to select all rows where the area exceeds the threshold, then assigns the value to the category column in a single vectorised operation. No loop. No cursor. The entire dataset updates through vectorised operations rather than Python loops. Runtime still depends on the dataset, implementation, machine, and verification method.

Pattern 3: Geoprocessing to GeoPandas methods

ARCPY

ArcPy chains geoprocessing calls by passing string layer names between tools. A Buffer writes to an intermediate layer by name, then Intersect reads that named layer as input. The workspace is the implicit link. This works well inside ArcGIS Pro, but makes scripts difficult to test in isolation and impossible to run outside an ArcGIS environment.

GEOPANDAS

GeoPandas passes GeoDataFrame objects directly between operations - no intermediate files, no string references. Call .buffer() on the roads GeoDataFrame (ensuring a projected CRS first), then pass the resulting geometry directly into gpd.overlay() with the parcels layer. The intersection runs in-memory. The critical detail: buffer distance is in the CRS units - always reproject to metres before buffering.

Handling arcpy.env

arcpy.env provides global settings that affect every geoprocessing operation. Open-source tools don't have this concept - each operation is explicit. Here's how to handle each setting.

arcpy.env SettingOpen-Source EquivalentNotes
workspaceWorking directory variableManual path management
overwriteOutputNo equivalent (always overwrites)Delete old files explicitly if needed
outputCoordinateSystemgdf.to_crs()Explicit per-operation
extentgdf.clip(extent_gdf)Explicit clipping
cellSizerasterio resolution parameterPer-operation
maskrasterio.mask.mask()Explicit masking
parallelProcessingFactordask-geopandasDifferent parallelism model

The shift from implicit (arcpy.env sets it once, everything inherits) to explicit (pass CRS, extent, and mask to each function) feels more verbose initially. In practice, explicit is better: you can see exactly what each operation does without hunting for global state set 200 lines earlier.

When to Keep ArcPy

Migration is not all-or-nothing. Keeping ArcPy for specific workflows is a legitimate engineering decision, not a failure. Here are the six scenarios where ArcPy remains the right tool.

1

Network Analysis Workflows

Service areas, closest facility, OD cost matrices. pgRouting exists but requires PostGIS setup and a different data model. If you depend on ESRI network datasets with turn restrictions and one-way streets, the migration effort outweighs the benefit.

2

Complex Raster Processing Chains

Multi-step raster workflows using Spatial Analyst - weighted overlay, cost distance, viewshed chaining. Replicating these in rasterio requires significantly more code and extensive testing. If the chain works and runs infrequently, leave it.

3

Cartographic Production

Map layouts, symbology, annotation. ArcGIS Pro's cartographic engine has no open-source equivalent at the same quality level. QGIS covers basic map production, but enterprise cartographic output still favours ArcGIS Pro.

4

Utility Network Integration

If your workflows touch Utility Network data, there is no migration path. Full stop. The Utility Network data model is proprietary to ArcGIS. This is not a technical limitation that will be solved - it's a vendor lock-in by design. If you are also dealing with the broader Utility Network migration deadline, review the Esri migration options available to your organisation.

5

When the Team Pushes Back

Migration requires buy-in. An analyst forced to use unfamiliar tools is less productive than one using familiar tools willingly. Address resistance through training and gradual adoption, not mandates. Start with the analysts who are interested and let results speak.

6

When Migration Cost Exceeds the Verified Licence Case

Do the arithmetic using current licence, implementation, training, validation, support, and risk costs. A historical payback example is not a current forecast. Long or uncertain payback periods carry execution risk.

Migration Timeline

For a typical 20-script inventory, this is the phase-by-phase timeline. Adjust durations based on your team size and script complexity.

Migration timeline phases from inventory through parallel testing to switch-over

MIGRATION PHASES

01

Inventory and Categorise

1 week

Find all scripts, categorise as Green/Yellow/Red/Grey. Document dependencies between scripts. Interview analysts about each workflow.

02

Migrate Green Scripts

2-3 weeks

Start with the easiest wins. Build confidence and establish patterns. Each Green script takes 2-8 hours. This phase also trains the team on GeoPandas idioms.

03

Migrate Yellow Scripts

2-3 weeks

Medium complexity. Requires refactoring arcpy.env patterns, cursor replacements, and field calculation logic. Each Yellow script takes 4-16 hours.

04

Parallel Testing

2 weeks minimum

Run old and new scripts on the same data. Compare every output using the comparison script. Fix discrepancies. Zero failures for 2 consecutive weeks before proceeding.

05

Red Scripts Decision

1 week

For each Red script: find a workaround (pgRouting, GRASS GIS), keep it in ArcPy, or redesign the workflow entirely. Document the decision and rationale.

06

Switch Over

1 week

Decommission old ArcPy scripts only after the evidence is accepted. Update documentation, train the team, and monitor the new workflow. Record parallel runs, validation results, discrepancies, and human approval before a production change.

TOTAL TIMELINE

Scope-specificduration for inventory and validation

The retained week ranges are historical planning examples. Set the duration from inventory size, dependencies, test fixtures, team capacity, and required approval. Parallel validation remains necessary wherever a comparison is meaningful.

What is an ArcPy migration playbook?

An ArcPy migration playbook is a structured, file-by-file strategy for inventory, categorisation, function mapping, parallel testing, and phased decisions. Run both versions only where the data and test fixtures support a meaningful comparison. Record discrepancies, human review, and the reason for each retain, rewrite, or redesign decision.

Frequently Asked Questions

Can I migrate ArcPy scripts to open source?

Many ArcPy patterns have possible equivalents in GeoPandas, rasterio, Shapely, or other libraries. Coverage depends on the function, data, runtime, licence, and validation requirements. Specialist capabilities need separate review.

How long does it take to migrate from ArcPy?

Timing depends on inventory size, dependencies, data, target runtime, test fixtures, review capacity, training, and operational ownership. The timeline examples in this retained article are historical planning examples, not a current forecast.

What is the best replacement for ArcPy?

GeoPandas is the closest equivalent for vector analysis (buffer, intersect, dissolve, spatial join). rasterio replaces Spatial Analyst for raster operations. Shapely handles geometry operations. For network analysis, pgRouting (PostGIS) or NetworkX are alternatives. No single library replaces all of ArcPy.

What is an ArcPy migration playbook?

An ArcPy migration playbook is a structured, file-by-file process for moving ArcPy scripts to open-source equivalents such as GeoPandas, rasterio, and Shapely. It covers inventory and categorisation, function mapping, parallel testing, and a phased switch-over plan. If your migration is driven by the broader Utility Network note, you may also need to consider the wider Esri migration path. Migration Engine is in development; any current workflow review must define its evidence, validation, and human-review boundary.

Migration is a file-by-file process, not a big-bang switch. Start with the Green scripts, build confidence, and let the parallel testing results justify the next phase.

The function mapping table and 12-gap analysis give you the full picture upfront. No surprises mid-project. The scripts that can't migrate stay in ArcPy - that's engineering pragmatism, not failure.

If you're starting from the business case, Part 1 covers the ROI analysis. For the full function-by-function reference with benchmarks, see our ArcPy to GeoPandas guide and the side-by-side benchmark comparison.

Get Workflow Automation Insights

Monthly tips on automating GIS workflows, open-source tools, and lessons from enterprise deployments. No spam.

PRODUCTION SPATIAL WORKFLOWS

Review the workflow behind this guide

Migration Engine is in development. A current workflow review should define inventory, categorisation, translation boundaries, output comparison, discrepancy handling, and human approval before a production change.

NEXT STEP

Discuss a migration workflow

Share the scripts, dependencies, target runtime, and validation question you need to review. A current scope must be based on the estate, not this historical article.