Why Are My Shapefile Column Names Truncated? How to Fix It

Problem statement

A common GIS problem is that saving a GeoDataFrame with gdf.to_file("out.shp") truncates your column names to 10 characters. In practice, this usually looks like one of these cases:

  • a warning is printed about field names being truncated
  • column names like population_total become population after saving
  • two long names collapse into the same short name, creating duplicate or garbled fields
  • the saved shapefile has different column names than the GeoDataFrame in memory

If you are trying to fix truncated shapefile column names, the cause is almost always the same single issue:

  • the shapefile format stores attributes in a dBASE (.dbf) table
  • the dBASE format limits field names to 10 characters
  • it also limits the number of fields (~254) and the data types it can store
  • any name longer than 10 characters is shortened on write, sometimes producing collisions

The goal is to either rename your columns deliberately so the short names stay readable, or switch to a modern format that has no such limit.

Quick answer

Truncated column names are a hard limit of the shapefile format, not a GeoPandas bug. You have two practical options:

  1. Keep the shapefile, but rename your columns to 10 characters or fewer before saving so you control the result.
  2. Save to a modern format like GeoPackage (.gpkg) or GeoJSON, which do not truncate field names.

The simplest fix is to stop using shapefiles for output. Save a GeoPackage instead:

import geopandas as gpd

gdf = gpd.read_file("data/census.shp")

# GeoPackage keeps full-length column names
gdf.to_file("data/census.gpkg", driver="GPKG")

A GeoPackage keeps population_total, median_household_income, and any other long names exactly as they are.

Step-by-step solution

1. Reproduce and read the truncation warning

When you write a shapefile with long column names, GeoPandas (through its I/O engine) emits a warning. Read it instead of ignoring it.

import geopandas as gpd

gdf = gpd.read_file("data/census.gpkg")
print(gdf.columns.tolist())

# This will warn about names longer than 10 characters
gdf.to_file("data/census.shp")

A typical warning looks like:

UserWarning: Normalized/laundered field name: 'population_total' to 'population'

That message tells you exactly which column was shortened and what it became.

2. Check which columns are too long

Before saving, list any column whose name exceeds the 10-character limit. This shows you the columns that will be affected.

too_long = [c for c in gdf.columns if c != gdf.geometry.name and len(c) > 10]
print("Will be truncated:", too_long)

If this list is empty, your shapefile export will keep the names as written.

3. Option A: rename columns to 10 characters or fewer

If you must produce a shapefile, rename the long columns yourself so you control the short names. Keep a lookup so you can recover the original names later.

import geopandas as gpd

gdf = gpd.read_file("data/census.gpkg")

rename_map = {
    "population_total": "pop_total",
    "median_household_income": "med_inc",
    "households_with_children": "hh_kids",
}

gdf = gdf.rename(columns=rename_map)
gdf.to_file("data/census.shp")

Because you chose the short names, there are no collisions and the table stays readable.

4. Option B: switch to a format without the limit

The cleanest fix is to stop saving shapefiles and use GeoPackage or GeoJSON. Both keep full-length names.

import geopandas as gpd

gdf = gpd.read_file("data/census.gpkg")

# GeoPackage: full names, single file, recommended
gdf.to_file("data/census_out.gpkg", driver="GPKG")

# GeoJSON: full names, text-based, good for the web
gdf.to_file("data/census_out.geojson", driver="GeoJSON")

Neither format truncates field names, so this avoids the problem entirely.

Code examples

Example 1: Build a long-to-short rename map and keep a lookup

import geopandas as gpd
import json

gdf = gpd.read_file("data/census.gpkg")

rename_map = {
    "population_total": "pop_total",
    "median_household_income": "med_inc",
    "households_with_children": "hh_kids",
    "unemployment_rate": "unemp_rt",
}

gdf = gdf.rename(columns=rename_map)
gdf.to_file("data/census.shp")

# Save the lookup so you can restore the original names later
with open("data/census_fields.json", "w") as f:
    json.dump(rename_map, f, indent=2)

Example 2: Restore the original names after reading the shapefile back

import geopandas as gpd
import json

gdf = gpd.read_file("data/census.shp")

with open("data/census_fields.json") as f:
    rename_map = json.load(f)

# Invert the saved lookup: short -> long
restore_map = {short: long for long, short in rename_map.items()}
gdf = gdf.rename(columns=restore_map)

print(gdf.columns.tolist())

Example 3: Save as GeoPackage to keep full column names

import geopandas as gpd

gdf = gpd.read_file("data/census.gpkg")

# Long names like "median_household_income" are preserved
gdf.to_file("data/census_out.gpkg", driver="GPKG")

check = gpd.read_file("data/census_out.gpkg")
print(check.columns.tolist())

Example 4: Save as GeoJSON to keep full column names

import geopandas as gpd

gdf = gpd.read_file("data/census.gpkg")

# GeoJSON is text-based and keeps full property names
gdf.to_file("data/census_out.geojson", driver="GeoJSON")

check = gpd.read_file("data/census_out.geojson")
print(check.columns.tolist())

Explanation

A shapefile is not a single file. It is a small set of files with the same base name, and attribute data lives in the .dbf file. The .dbf format is dBASE, a database format from the 1980s.

dBASE was designed long before modern naming conventions, and it imposes several fixed limits:

  • field names are stored in a fixed 11-byte header slot, which works out to a maximum of 10 usable characters
  • a table can hold roughly 254 fields
  • field types are limited to a small set, and numeric fields have fixed width and precision

When you call gdf.to_file("out.shp"), the I/O engine has to fit your column names into that 10-character slot. Any longer name is shortened automatically. If two long names share the same first characters, the shortened versions can collide, and the engine appends or alters characters to keep them unique. That is where duplicate or garbled names come from.

This is a property of the format, so no GeoPandas setting removes it. The only real choices are to shorten the names yourself or to use a format that was not built around dBASE.

Edge cases or notes

The ~254-field limit

Field count: A shapefile can store roughly 254 attribute fields. If you have a very wide table, exporting to a shapefile may drop or refuse columns. GeoPackage has no practical field-count limit for normal use.

Field type limits

Data types: The .dbf format supports only a few field types. Long integers, full-precision floats, datetimes with time zones, and list-like values may be coerced, truncated, or lost. GeoPackage and GeoJSON preserve richer types.

Encoding

Text encoding: Older shapefiles relied on a separate .cpg file to describe text encoding. Non-ASCII characters in field names or values can be mangled on round-trip. Modern formats use UTF-8 by default.

Mixed-case names

Case sensitivity: dBASE field names are not reliably case-sensitive, so Pop_Total and pop_total may not survive as distinct columns. Use lowercase short names to avoid surprises.

Silent collisions

Duplicate short names: If population_total and population_density both shorten toward population, the result can be population and a numbered or altered variant. Always check the saved column names after writing a shapefile.

FAQ

Why does GeoPandas shorten my column names when I save a shapefile?

Because the shapefile attribute table uses the dBASE (.dbf) format, which limits field names to 10 characters. GeoPandas truncates longer names to fit the format and warns you when it does.

Can I turn off the 10-character limit in GeoPandas?

No. The limit comes from the shapefile format itself, not from GeoPandas. To keep full-length names, rename your columns to 10 characters or fewer, or save to GeoPackage or GeoJSON instead.

How do I keep my original long names when I have to deliver a shapefile?

Build a rename map from long to short names, apply it with gdf.rename(columns=...), and save the mapping to a file like JSON. You can re-apply the inverse mapping after reading the shapefile back.

Which format should I use instead of a shapefile?

GeoPackage (.gpkg) is the best general-purpose choice: one file, full-length names, and rich data types. GeoJSON is a good option when you need a text-based format for the web.

How can I detect which columns will collide before saving a shapefile?

Map each column to its 10-character form and look for duplicates: build the truncated names with [c[:10] for c in gdf.columns] and check whether any short name appears more than once. If duplicates exist, rename those columns deliberately before writing so you control the result.

Does saving to GeoPackage have any field name length limit?

No. GeoPackage stores attributes in SQLite, so it keeps full-length names like median_household_income and has no practical 10-character or 254-field limit. Save it with gdf.to_file("out.gpkg", driver="GPKG").

Will the geometry column name also get truncated in a shapefile?

The geometry itself is stored separately from the .dbf attribute table, so the active geometry column is not written as a truncated attribute field. Only the attribute column names are subject to the 10-character dBASE limit.

My field names are short enough but the values are still cut off. Why?

That is a separate dBASE limit on field width and type, not the 10-character name limit; long text values and high-precision numbers can be truncated or coerced on write. Save to GeoPackage or GeoJSON, which preserve longer text and richer numeric types.