The short answer
Assigning a CRS changes only the metadata label that declares what the existing coordinate numbers mean — the X and Y values in the file do not change. Reprojecting recomputes those numbers into a different coordinate system; the file ends up with different X and Y values that point to the same places on Earth. You assign when the coordinates are already correct but the file is mislabelled or unlabelled. You reproject when the coordinates are correctly labelled and you need them in a different frame for display, analysis, or delivery. Mixing these up is the single most common silent error in GIS, because the map can look fine while the underlying geometry is meaningless.
The mechanism, precisely
A spatial file stores two separate things: the coordinate numbers (the geometry) and the CRS definition (the metadata that tells software how to interpret those numbers).
- Assign = rewrite the metadata only.
(315000, 5089000)stays(315000, 5089000); you have just changed the claim about what those numbers are. - Reproject = run the numbers through a coordinate operation (projection plus, if needed, a datum transformation) and write new numbers.
(315000, 5089000)in UTM 32N becomes(6.15, 45.91)in WGS84 lat/long — different numbers, identical real-world location.
The litmus test: did the numbers change? If yes, you reprojected. If only the label changed, you assigned.
The diagnostic: read the numbers
You can almost always tell which operation you need by looking at the coordinate values themselves, because each CRS has a characteristic range and unit.
- Geographic (lat/long), e.g. EPSG:4326: small numbers, longitude in −180…180, latitude in −90…90, with decimals.
6.15, 45.91is unmistakably degrees. - UTM, e.g. EPSG:32632: easting in 100,000–900,000, northing up to ~10,000,000 (northern hemisphere).
315000, 5089000is metres in a UTM zone. - Web Mercator, EPSG:3857: very large metre values, often in the millions, e.g.
684000, 5750000or larger.
So if a file's numbers look like 6.15, 45.91 but the metadata says UTM, the metadata is wrong: assign EPSG:4326. If the numbers are genuinely degrees and you need metres for buffering, reproject to a UTM zone. If a layer with degree values is assigned a UTM CRS, software reads 6.15 as 6.15 metres east of the zone's false origin and the layer collapses to a point near the equator off the West African coast — the classic "my data is in the Gulf of Guinea" symptom.
Worked example: the GDAL and QGIS commands
Case A — wrong/missing label, numbers already correct (assign). A shapefile holds lon/lat but the .prj is missing or says UTM:
# Vector: relabel only, no geometry change
ogr2ogr -a_srs EPSG:4326 fixed.gpkg broken.shp
# Raster: relabel only
gdal_edit.py -a_srs EPSG:4326 broken.tif
-a_srs ("assign SRS") writes the CRS definition and touches nothing else. gdal_edit.py edits in place, so keep a backup.
Case B — correct label, need a different frame (reproject). The data is genuinely WGS84 and you need UTM 32N metres for analysis:
# Vector: recompute coordinates
ogr2ogr -t_srs EPSG:32632 utm.gpkg wgs84.gpkg
# Raster: recompute and resample
gdalwarp -s_srs EPSG:4326 -t_srs EPSG:32632 -tr 10 10 -r bilinear wgs84.tif utm.tif
-t_srs ("target SRS") with a known -s_srs runs the transformation. In QGIS, opening Layer Properties → Information and setting the layer CRS performs an assign (it does not move the data); using Export → Save Features As or Reproject Layer in the Processing toolbox performs a reproject. In PostGIS the same split exists: ST_SetSRID(geom, 4326) assigns the label, while ST_Transform(geom, 32632) reprojects — using ST_Transform on geometry that has the wrong SRID gives a wrong result, so assign first if the SRID is wrong.
A safe decision procedure
- Inspect the actual coordinate values (
ogrinfo -al -so, the QGIS attribute/identify tools, orgdalinfo). - Decide which CRS the numbers are really in, from their range and unit.
- If the file's declared CRS does not match that reality, assign the correct one first. Do not reproject yet.
- Once the label is correct, reproject into the CRS your analysis or delivery needs.
- Keep the original file untouched until step 3 is verified against a control point.
The fatal shortcut is skipping straight to reprojection while the source label is wrong: gdalwarp trusts -s_srs, so transforming from a false source CRS produces confidently wrong output.
Common pitfalls and why they happen
- Dragging by relabelling. Cycling the layer CRS until the data lands on the basemap. It sometimes "works" visually but corrupts the geometry's meaning; the next measurement is wrong.
- Reprojecting from a wrong source CRS. The transformation math is correct but starts from a false premise, so the result is wrong with no error message.
- Editing the
.prjto move a shapefile. Same as assigning — it relabels, it does not transform. - Forgetting the datum. Assigning EPSG:4326 when the data is actually NAD27 lat/long fixes the unit but leaves a metre-scale datum error; you still need a reprojection with the right transformation.
gdal_edit.pyin place without a backup. If you assign the wrong CRS you have overwritten the only record of the correct one.
Validation
After assigning, overlay the layer on a trusted reference (a basemap, a known boundary). If it now lands in the right place, the assignment was correct. After reprojecting, measure a known distance or check a surveyed control point in the new CRS — the value should match the published figure within the transformation's stated accuracy. Confirm with gdalinfo/ogrinfo that the CRS authority code is what you intended and that the corner coordinates have the expected magnitude for that CRS.
Bathyl perspective
We separate the two operations explicitly in every pipeline: a label-correction step (assign) that is verified against a control point, then a transformation step (reproject) into the analysis frame, with both CRS codes and any datum transformation recorded with the deliverable. The result is a coordinate chain another analyst can audit end to end.