4.6 EPSG Codes, WKT, and PROJ Strings
How CRS definitions are actually stored and exchanged across tools — and how to read them.
Key takeaways
- EPSG codes are short integers referring to formal CRS definitions.
- WKT is the human-readable text form; PROJ strings are the compact CLI form.
- Knowing how to parse these formats saves hours of debugging.
Introduction
Every CRS has three common representations:
- EPSG code — a short integer (
4326,3857,27700, …). - WKT — verbose text describing every parameter.
- PROJ string — compact CLI-friendly form (
+proj=utm +zone=10 +datum=WGS84 +units=m).
This lesson shows you how to read each, when to use each, and how to look them up.
EPSG codes
EPSG codes are maintained by the EPSG registry (formerly the European Petroleum Survey Group, now IOGP). Every commonly-used CRS has a unique integer code. Examples:
| Code | CRS |
|---|---|
| 4326 | WGS 84 (lat/lon) |
| 3857 | Web Mercator |
| 4269 | NAD83 (lat/lon) |
| 26910 | NAD83 / UTM Zone 10N |
| 27700 | British National Grid |
| 2154 | RGF93 / Lambert-93 (France) |
| 25832 | ETRS89 / UTM Zone 32N (Germany) |
| 5070 | NAD83 / Conus Albers |
| 3031 | WGS84 / Antarctic Polar Stereographic |
| 3035 | ETRS89 / Lambert Azimuthal Equal Area (Europe) |
Look up any code at epsg.io.
Advantages:
- Compact — five digits.
- Unambiguous — every tool agrees what 4326 means.
- Easy to compare — same code everywhere.
Disadvantages:
- Opaque — "4326" tells a beginner nothing.
- Custom CRSs have no code.
WKT (Well-Known Text)
WKT is a verbose, nested text representation of a CRS. Two versions exist: WKT 1 (legacy) and WKT 2 (modern, OGC-standardised). PROJ 6+ uses WKT 2.
Example WKT 2 for EPSG:4326:
1GEOGCRS["WGS 84",
2 DATUM["World Geodetic System 1984",
3 ELLIPSOID["WGS 84",6378137,298.257223563,
4 LENGTHUNIT["metre",1]]],
5 PRIMEM["Greenwich",0,
6 ANGLEUNIT["degree",0.0174532925199433]],
7 CS[ellipsoidal,2],
8 AXIS["geodetic latitude (Lat)",north,
9 ORDER[1],
10 ANGLEUNIT["degree",0.0174532925199433]],
11 AXIS["geodetic longitude (Lon)",east,
12 ORDER[2],
13 ANGLEUNIT["degree",0.0174532925199433]],
14 USAGE[
15 SCOPE["Horizontal component of 3D system."],
16 AREA["World."],
17 BBOX[-90,-180,90,180]],
18 ID["EPSG",4326]]Read this tree top-down: it's a geographic CRS, uses the WGS 84 datum / ellipsoid, Greenwich prime meridian, axis order is (latitude, longitude). The last clause gives the EPSG identifier.
Shapefiles store WKT in the .prj file. GeoTIFFs embed WKT in metadata tags.
PROJ strings
PROJ strings are a compact CLI representation, used by the PROJ library and older tools. Example:
+proj=utm +zone=10 +ellps=WGS84 +datum=WGS84 +units=m +no_defsOr for WGS 84 geographic:
+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defsPROJ strings are powerful for custom definitions (oblique Mercators, arbitrary datums). They predate the EPSG registry in many tools and still appear in older configuration files.
When to prefer each form
- EPSG code — 99% of the time. It's the lingua franca.
- WKT 2 — when you need the full definition in a file (GeoTIFF, GeoPackage,
.prj). - PROJ string — CLI work with
proj,cs2cs, or when defining a custom CRS not in the EPSG registry.
How tools consume CRS info
Different tools accept different forms:
1# GeoPandas — accepts any of these
2gdf.to_crs('EPSG:3857')
3gdf.to_crs(3857)
4gdf.to_crs('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
5gdf.to_crs('GEOGCRS["WGS 84", ...]') # full WKT1# gdalwarp
2gdalwarp -t_srs EPSG:3857 input.tif output.tif
3gdalwarp -t_srs "+proj=utm +zone=10 +datum=WGS84" input.tif output.tif
4gdalwarp -t_srs "$(cat custom.wkt)" input.tif output.tifDefining a custom CRS
Occasionally you need a CRS not in EPSG. Examples: an oblique Mercator tuned to the axis of a single pipeline, or a small-island projection custom-made for an archipelago.
PROJ string for an oblique Mercator along a specific great circle:
1+proj=omerc +lat_0=45 +lonc=-74 +alpha=45 +k_0=1 +x_0=0 +y_0=0
2+gamma=0 +ellps=WGS84 +units=m +no_defsOnce defined, save it as a WKT .prj alongside your data. Most tools will honour it.
Common lookups you'll need
- epsg.io — fastest way to find a CRS. Try "UTM zone 32N" or "Paris".
projinfo EPSG:XXXX— PROJ CLI tool prints all representations.- PROJ database file —
proj.dbcontains everything; rarely queried directly but underpins everything. - GeoPandas —
gpd.read_file(path).crsshows current CRS in WKT. - ogr2ogr —
ogr2ogr -t_srs EPSG:XXXXreprojects anything.
A quick projinfo example
1$ projinfo EPSG:4326
2PROJ.4 string:
3+proj=longlat +datum=WGS84 +no_defs +type=crs
4[object Object]
5[object Object]
6One command, all three representations.
Custom vertical CRSs
Height reference systems have their own EPSG codes, separate from horizontal CRSs:
- EPSG:5703 — NAVD88 (North American vertical datum).
- EPSG:3855 — EGM2008 geoid.
- EPSG:5773 — EGM96.
A compound CRS combines horizontal + vertical (e.g., NAD83 + NAVD88). Most GIS work treats vertical separately, but for surveying and engineering a compound CRS is the right choice.
Self-check exercises
1. What's the difference between EPSG:4326 and EPSG:3857?
EPSG:4326 is WGS 84 geographic — lat/lon in degrees. EPSG:3857 is Web Mercator — projected metres, used by consumer tile servers. They share the WGS 84 datum but differ in projection. Data from 4326 must be reprojected (not just relabeled) to use in 3857.
2. You find a shapefile with no .prj. How do you determine its CRS?
Open the data, inspect coordinate magnitudes and extent: lat/lon range → EPSG:4326; 500 000 ± easting with 4-million-ish northing → UTM; 100 000–700 000 easting and 0–1 400 000 northing → British National Grid. Cross-check with any project documentation. Always attempt to recover from source metadata before guessing — an incorrect CRS label propagates errors widely.
3. When would you define a CRS with a PROJ string rather than an EPSG code?
When the CRS you need isn't in the EPSG registry — for example, a custom oblique Mercator tuned to a pipeline corridor, a local site plane for a mine, or a variant of an official projection with different parameters. PROJ strings give full control over parameters; EPSG codes are the right choice when a standard CRS already captures what you need.
Summary
- EPSG codes are the default way to refer to CRSs.
- WKT is the authoritative, verbose text form embedded in files.
- PROJ strings are the compact CLI form, essential for custom CRSs.
projinfo,epsg.io, and library functions expose all three representations.
Further reading
- EPSG Registry — official CRS database.
- PROJ documentation — WKT 2 and PROJ string reference.
- Eurostat GISCO — catalog of European reference CRSs.
- OGC — Well-Known Text Representation of Coordinate Reference Systems (18-010r11).