Maritime boundaries explained: EEZ, territorial sea and baselines

Problem statement

Maritime zones are defined as distances from a line, and almost every mistake in working with them comes from getting either the line or the distance wrong. The line is the baseline, which is not the coastline; the distances are in nautical miles, which are not kilometres; and the buffers are geodesic, which a projected or degree-space buffer is not.

The scale of the last error is worth stating first. A 200 nautical mile zone around Iceland, computed correctly in an equal-area projection, covers 1,094,690 kmยฒ. The same buffer applied in degrees covers 736,832 kmยฒ โ€” 32.7% smaller, and wrong in a way that looks entirely plausible on a map.

Quick answer

Buffer in a projection suited to the area, with the distance in metres:

import geopandas as gpd
from pyproj import CRS

NM = 1852.0                                   # one nautical mile, exactly

area_crs = CRS.from_proj4("+proj=laea +lat_0=65 +lon_0=-19 +datum=WGS84 +units=m")
land = coast.to_crs(area_crs)
eez = land.buffer(200 * NM).union_all()

print(f"{gpd.GeoSeries([eez], crs=area_crs).area.iloc[0] / 1e6:,.0f} kmยฒ")
1,094,690 kmยฒ

An azimuthal equidistant or Lambert azimuthal equal-area projection centred on the area keeps both the distance and the area honest over a few thousand kilometres. A single global projection does neither.

Stack of maritime zones from the baseline out to the high seas with the distance and rights at each.
Five zones, all measured from the baseline rather than from the visible coast.

Step-by-step solution

1. Know the zones and their distances

zone distance from the baseline in brief
internal waters landward of the baseline full sovereignty
territorial sea 12 NM sovereignty, with innocent passage
contiguous zone 24 NM customs, immigration, sanitary enforcement
exclusive economic zone 200 NM resource rights, not sovereignty
continental shelf 200 NM, extendable to 350 NM seabed resources
high seas beyond the EEZ nobody's

2. Understand that the baseline is not the coastline

The normal baseline is the low-water line along the coast as marked on official large-scale charts. Straight baselines may be drawn across deeply indented coasts and fringing islands, and bay closing lines across the mouths of legal bays. Those straight segments can cut off large areas, and they are where the legal and the geometric answers diverge.

3. Use nautical miles correctly

One nautical mile is exactly 1,852 m. It is not a minute of longitude except at the equator, and it is not 1,000 m. A 200 NM zone is 370.4 km.

4. Buffer geodesically, or in a projection that behaves

A buffer in degrees applies the same number to latitude and longitude, so it becomes an ellipse whose eastโ€“west extent is wrong by 1/cos(latitude). At 65ยฐN that factor is 2.37, which is why the degree-space Iceland zone came out a third too small.

5. Expect overlaps, and do not resolve them yourself

Where opposite or adjacent coasts are less than 400 NM apart, the theoretical EEZs overlap. The actual boundary is a treaty or an equidistance line, and there are many unresolved cases. A computed buffer is a geometric estimate, never an authoritative boundary.

6. Use a published boundary layer when the answer matters

Marine Regions' World EEZ and the national hydrographic offices publish authoritative maritime boundaries with their treaty basis. Compute a buffer only for analysis, illustration or a first approximation, and say which you did.

7. Handle the antimeridian before you do anything else

Many EEZs cross it. A country such as Fiji is stored as parts spanning the full โˆ’180 to 180 range, and every naive operation โ€” centroid, bounding box, buffer, dissolve โ€” produces nonsense.

Scene showing a normal baseline following the low-water line and straight baselines cutting across a fjorded coast.
Straight baselines enclose water that a normal baseline would leave outside.

Code examples

Example 1 โ€” zones as nested buffers, measured

import geopandas as gpd
from pyproj import CRS

NM = 1852.0
ZONES = {"territorial sea": 12, "contiguous zone": 24,
         "EEZ": 200, "extended shelf": 350}

area_crs = CRS.from_proj4("+proj=laea +lat_0=65 +lon_0=-19 +datum=WGS84 +units=m")
land = coast.to_crs(area_crs)
land_area = land.area.sum() / 1e6

rows = []
for name, nm in ZONES.items():
    poly = land.buffer(nm * NM).union_all()
    total = gpd.GeoSeries([poly], crs=area_crs).area.iloc[0] / 1e6
    rows.append({"zone": name, "nm": nm, "km": nm * NM / 1000,
                 "total_km2": round(total), "sea_km2": round(total - land_area)})
print(gpd.pd.DataFrame(rows).to_string(index=False))

On the Iceland clip, land is 102,428 kmยฒ and the 200 NM zone totals 1,094,690 kmยฒ, leaving 992,262 kmยฒ of sea.

Example 2 โ€” what a degree-space buffer costs

import geopandas as gpd

NM = 1852.0
proper = land_projected.buffer(200 * NM).union_all()
naive = land_geographic.buffer(200 * NM / 111_320.0).union_all()   # degrees

a = gpd.GeoSeries([proper], crs=area_crs).area.iloc[0]
b = gpd.GeoSeries([naive], crs=4326).to_crs(area_crs).area.iloc[0]
print(f"projected buffer: {a/1e6:,.0f} kmยฒ")
print(f"degree buffer   : {b/1e6:,.0f} kmยฒ ({b/a - 1:+.1%})")
projected buffer: 1,094,690 kmยฒ
degree buffer   :   736,832 kmยฒ (-32.7%)

Example 3 โ€” a true geodesic buffer, point by point

import numpy as np
from pyproj import Geod
from shapely.geometry import Polygon
from shapely.ops import unary_union

geod = Geod(ellps="WGS84")

def geodesic_buffer(line_coords, distance_m, steps=72):
    """Union of geodesic circles along a line โ€” exact, and slow."""
    circles = []
    for lon, lat in line_coords:
        az = np.linspace(0, 360, steps, endpoint=False)
        lons, lats, _ = geod.fwd(np.full(steps, lon), np.full(steps, lat),
                                 az, np.full(steps, distance_m))
        circles.append(Polygon(zip(lons, lats)))
    return unary_union(circles)

Use this to validate a projected buffer rather than to produce one: it is exact on the ellipsoid and far too slow for a real coastline, but running it on a few dozen sampled vertices tells you whether your projection choice is good enough.

Explanation

Why the baseline matters more than the coastline

Every zone is measured from the baseline, and a straight baseline across a fjorded coast can sit tens of kilometres seaward of the low-water line. Norway's straight baselines, upheld in the 1951 Anglo-Norwegian Fisheries case, are the classic example: the EEZ computed from the coast and the EEZ computed from the baseline differ substantially. A buffer from a coastline layer is therefore an approximation with a known direction of error โ€” it understates the zone.

Why projected buffers are acceptable and degree buffers are not

A buffer in a projected CRS applies the distance in the projection's units, so the error is the projection's distortion at that place โ€” a few percent for a well-chosen local projection over a few hundred kilometres. A buffer in degrees applies the same angular distance to latitude and longitude, so it is wrong by 1/cos(latitude) in one direction. At 65ยฐN that is more than a factor of two, which compounds into the 32.7% area error measured above.

Why 200 NM produces so much sea

370.4 km of buffer around even a small island group encloses an enormous area, because area grows with the square of the radius. Iceland's 102,428 kmยฒ of land generates 992,262 kmยฒ of sea โ€” nearly ten times its land area โ€” and small remote islands generate far larger ratios. That arithmetic is why remote islands are geopolitically valuable.

Why an overlap is not a bug

The convention allocates zones up to 200 NM, and where coasts are closer than 400 NM the entitlements overlap. Resolution is by agreement, usually along a median line but not always, and many boundaries are unsettled. Any code that dissolves overlapping buffers into a partition is inventing a boundary.

Bars comparing a 200 nautical mile zone around Iceland computed in a projected CRS, its sea-only area, and the same buffer applied in degrees.
At 65ยฐN a degree buffer is wrong by more than a factor of two eastโ€“west.

Edge cases or notes

  • 1 NM is exactly 1,852 m. Not a minute of longitude.
  • Rocks that cannot sustain habitation generate no EEZ, only a territorial sea.
  • Archipelagic baselines are a separate regime for archipelagic states.
  • The extended shelf needs a submission to the CLCS and is not automatic.
  • Overlaps are normal. Do not resolve them geometrically.
  • The antimeridian breaks everything. Split or shift before any operation.
  • Use an authoritative layer for anything official. A buffer is an estimate.
  • Low-tide elevations can move a baseline. They are chart features, not coastline.

FAQ

How far out does an exclusive economic zone go?

200 nautical miles โ€” 370.4 km โ€” from the baseline, with the continental shelf extendable to 350 NM in some circumstances.

Is the baseline the same as the coastline?

No. The normal baseline is the charted low-water line, and straight baselines may be drawn across indented coasts and fringing islands, sometimes far seaward of the visible coast.

Can I just buffer the coastline by 200 NM?

For analysis or illustration, yes, in a suitable projection. It understates the zone wherever straight baselines apply, and it is never an authoritative boundary.

Why is my EEZ a third too small?

Almost certainly a buffer applied in degrees. At 65ยฐN that produces an area 32.7% smaller than the same buffer applied in metres.

What do I do where two EEZs overlap?

Nothing geometric. Overlaps are resolved by treaty or by an agreed median line, and many remain unsettled. Use a published boundary layer.

How many kilometres is a nautical mile?

Exactly 1.852 km, so 200 NM is 370.4 km.