Angkor Wat Hydraulic System

How the Khmer Empire Engineered Water, Power, and a City of One Million

Author

Ryan Lafferty

Published

March 28, 2026

The Scale of the Impossible

The West Baray holds 53 million cubic meters of water. It was dug by hand.

Workers moved an estimated 8 million cubic meters of earth to build its dikes, which rise nearly 12 meters above the surrounding plain and extend 8 kilometers from end to end. At their widest point the dikes are broad enough to walk across comfortably. The reservoir they contain is large enough to be visible from space, a perfect rectangle of water pressed into the Cambodian plain west of Angkor Thom, more or less unchanged since the 11th century.

It is one of four barays, the massive artificial reservoirs that defined the Khmer Empire’s relationship with water. Together they represent a hydraulic engineering program unmatched in the pre-industrial world outside of the great river civilizations, and in some ways surpassing them: the barays were not built beside a natural river system but imposed on a flat, seasonally flooded plain using captured monsoon runoff and carefully engineered gradients. The Khmer did not exploit geography. They rewrote it.

Data and Setup

Show code
import os
import sys
import warnings
import json

warnings.filterwarnings("ignore")

import pandas as pd
import geopandas as gpd
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.lines import Line2D
import folium
from folium.plugins import Fullscreen, MiniMap
from dotenv import load_dotenv
from sqlalchemy import create_engine

load_dotenv("../.env")

# PostGIS connection
conn_str = (
    f"postgresql://{os.environ['PG_USER']}:{os.environ['PG_PASSWORD']}"
    f"@{os.environ['PG_HOST']}:{os.environ['PG_PORT']}/{os.environ['PG_DBNAME']}"
)
engine = create_engine(conn_str)

# Load spatial data from PostGIS
barays      = gpd.read_postgis("SELECT * FROM angkor_barays",      engine, geom_col="geom")
temples     = gpd.read_postgis("SELECT * FROM angkor_temples",     engine, geom_col="geom")
waterways   = gpd.read_postgis("SELECT * FROM angkor_waterways",   engine, geom_col="geom")
mebons      = gpd.read_postgis("SELECT * FROM angkor_mebon_temples", engine, geom_col="geom")

# Ensure WGS84
barays    = barays.to_crs(epsg=4326)
temples   = temples.to_crs(epsg=4326)
waterways = waterways.to_crs(epsg=4326)
mebons    = mebons.to_crs(epsg=4326)

def drop_timestamps(gdf):
    """Remove datetime columns that Folium cannot JSON-serialize."""
    ts_cols = [c for c in gdf.columns if str(gdf[c].dtype).startswith("datetime")]
    return gdf.drop(columns=ts_cols)

barays    = drop_timestamps(barays)
temples   = drop_timestamps(temples)
waterways = drop_timestamps(waterways)
mebons    = drop_timestamps(mebons)

print(f"Barays:     {len(barays):>4} features")
print(f"Temples:    {len(temples):>4} features")
print(f"Waterways:  {len(waterways):>4} features")
print(f"Mebons:     {len(mebons):>4} features (seeded from research)")
Barays:       78 features
Temples:      12 features
Waterways:   335 features
Mebons:        2 features (seeded from research)

The Empire and Its Capital

The Khmer Empire held its shape for more than six centuries, from the declaration of Jayavarman II as chakravartin (universal ruler) on Phnom Kulen in 802 CE to the sacking of Angkor by the Ayutthaya Kingdom in 1431. At its peak, between the 11th and 13th centuries, it controlled or vassalized much of mainland Southeast Asia. The capital, Angkor, was not a city in the usual sense but a sprawling low-density urban system of temples, residential compounds, rice paddies, and waterways spread across roughly 1,000 square kilometers. Its population at peak is estimated between 750,000 and one million, which would rank it among the largest pre-industrial urban centers on Earth.

That population was fed almost entirely by rice. Three harvests per year were possible when water was reliable. Reliability, in a monsoon climate with a six-month dry season, required infrastructure. The barays were that infrastructure.

Show code
baray_data = {
    "Baray": ["East Baray (Yashodharatataka)", "West Baray"],
    "Built by": ["Yasovarman I", "Suryavarman I / Udayadityavarman II"],
    "Constructed": ["~900 CE", "1000–1066 CE"],
    "Length (km)": [7.5, 8.0],
    "Width (km)": [1.8, 2.2],
    "Dike height (m)": ["~3–4", "~12"],
    "Capacity (million m³)": ["36–55", "53"],
    "Island temple": ["East Mebon (953 CE)", "West Mebon (~1060 CE)"],
    "Current status": ["Dry — farmed today", "Partially filled — active lake"],
}

df = pd.DataFrame(baray_data)
df.set_index("Baray", inplace=True)
df
Built by Constructed Length (km) Width (km) Dike height (m) Capacity (million m³) Island temple Current status
Baray
East Baray (Yashodharatataka) Yasovarman I ~900 CE 7.5 1.8 ~3–4 36–55 East Mebon (953 CE) Dry — farmed today
West Baray Suryavarman I / Udayadityavarman II 1000–1066 CE 8.0 2.2 ~12 53 West Mebon (~1060 CE) Partially filled — active lake

The Hydraulic Machine

Sacred Headwaters: Kbal Spean

The hydraulic system’s source was Phnom Kulen, the sacred highland plateau the Khmer regarded as the birthplace of Angkor. At Kbal Spean, on the plateau’s river, artisans carved more than 1,000 lingas directly into the riverbed stone. These were symbols of Shiva, cut so that every drop of monsoon runoff passed over consecrated relief before flowing downstream into the plain. The Khmer made no distinction between the sacred and the hydraulic. Water that entered the city’s canals, filled the barays, and surrounded the temples had already been blessed at the source. Function and cosmology began at the same point.

Collecting the Monsoon

The Kulen Hills, a sandstone massif 40 kilometers northeast of Angkor, receive the first and heaviest monsoon rains each season. Khmer engineers channeled the runoff from these hills into the Siem Reap River, then rerouted and canalized the river to feed the barays and the city’s moats. The engineering was not spectacular in any single structure but in its cumulative precision: the gradients were shallow, the channels wide, and the entire system was designed to fill slowly and drain slowly, moderating the extreme seasonality of the Cambodian climate.

The moats around Angkor Wat and Angkor Thom were not decorative. Below ground they helped regulate the water table, keeping the clay-rich laterite soil saturated enough to prevent cracking but not so saturated as to undermine the foundation stones. Temple stability and water management were not separate engineering problems. They were the same problem.

Foundation Engineering

The sandy Angkor plain could not support the weight of stone temples without active management. Khmer engineers discovered that maintaining saturated subsoil created a far more stable and incompressible foundation. Every major temple was surrounded by moats or ponds that served as water reserves. Keeping the soil uniformly wet prevented the differential settlement and cracking that would have destabilized the tower foundations. Modern engineering studies confirm that this principle still protects the temples today: where adjacent monuments have lost their hydraulic connectivity and dried out, they have failed structurally. Where the water system has held, so have the buildings.

The stones required a logistics system to match. Sandstone blocks for Angkor Wat were quarried at the Kulen Mountains roughly 40 kilometers north and transported to the plain via barges and canals. Some blocks weighed several tons. The canal network that irrigated the rice fields also moved the building materials. The same infrastructure that fed the city built it.

The Village Scale

The infrastructure did not stop at the barays. Across the plain, households and village clusters dug smaller ponds called trapeangs for drinking water and kitchen gardens. The trapeangs connected to the broader canal network during the wet season and held enough water to see a household through the dry months. The system was coherent from the regional scale down to the individual plot, a hydraulic gradient from the Kulen Hills to the rice paddy to the garden pond.

Show code
canal_types = waterways["waterway"].value_counts().reset_index()
canal_types.columns = ["Waterway Type", "Feature Count"]
canal_types
Waterway Type Feature Count
0 canal 177
1 stream 100
2 drain 34
3 ditch 24

Three Harvests

The arithmetic of Angkor’s prosperity rests on a simple fact: dry-season rice cultivation requires irrigation, and irrigation at scale requires infrastructure. Without the barays and canal network, the Cambodian plain produces one rice harvest per year, during and immediately after the monsoon. With reliable irrigation, the number rises to two or three. Doubling or tripling agricultural output on the same land is the material foundation of the entire empire: the tax revenue, the labor mobilization, the temple construction, the military capacity.

The barays were not monuments to surplus. They were the mechanism of surplus.

The Two Barays

East Baray

Yasovarman I built the East Baray around 900 CE as part of the establishment of his capital, Yashodharapura. Its construction required moving approximately 8 million cubic meters of fill into the enclosing dikes. At full capacity it held between 36 and 55 million cubic meters of water across an area of 7.5 by 1.8 kilometers.

The East Baray is now dry. Farmers cultivate rice on its bed. Its outline is visible in satellite imagery, and the East Mebon, built in 953 CE on an artificial island at the baray’s center, now stands in open paddy fields where water once surrounded it on all sides.

West Baray

The West Baray is the largest. Its construction stretched across the reigns of Suryavarman I and Udayadityavarman II, beginning around 1000 CE and completing around 1066. At 8 kilometers by 2.2 kilometers, with earthen dikes rising nearly 12 meters, it remains one of the largest hand-excavated water features on Earth.

Unlike the East Baray, the West Baray still holds water. A lake occupies roughly two-thirds of its western portion, fed by seasonal rains and an intact intake channel. It is used for irrigation and fishing today. The West Mebon, an 11th-century temple on an artificial island, is still accessible only by boat.

Show code
# Parchment palette for light-register page
BG       = "#f5f0e6"
WATER    = "#5a8ab0"
WATER_E  = "#7aafcc"
TEMPLE   = "#8a6820"
TEMPLE_E = "#c9a84c"
CANAL    = "#6a9aaa"
TEXT     = "#201c10"
SPINE    = "#8a6820"
LEGEND_E = "#8a6820"

fig, ax = plt.subplots(1, 1, figsize=(14, 9))
fig.patch.set_facecolor(BG)
ax.set_facecolor(BG)

# Angkor region bounding box
ax.set_xlim(103.68, 104.08)
ax.set_ylim(13.28, 13.58)

# Waterways
if not waterways.empty:
    waterways.plot(ax=ax, color=CANAL, linewidth=0.4, alpha=0.6, label="Canals & Waterways")

# Barays
if not barays.empty:
    barays.plot(ax=ax, color=WATER, edgecolor=WATER_E, linewidth=0.8, alpha=0.5, label="Barays (OSM)")

# Temples
if not temples.empty:
    temples.plot(ax=ax, color=TEMPLE, edgecolor=TEMPLE_E, linewidth=0.5, alpha=0.65, label="Temples")

# Mebon temple points
for _, row in mebons.iterrows():
    ax.plot(
        row.geom.x, row.geom.y,
        "o", color=TEMPLE, markersize=8, zorder=5,
        markeredgecolor=TEMPLE_E, markeredgewidth=1.2,
    )
    ax.annotate(
        row["name"],
        xy=(row.geom.x, row.geom.y),
        xytext=(6, 6), textcoords="offset points",
        fontsize=8, color=TEXT,
    )

# Legend
legend_elements = [
    mpatches.Patch(facecolor=WATER, edgecolor=WATER_E, alpha=0.6, label="Barays"),
    mpatches.Patch(facecolor=TEMPLE, edgecolor=TEMPLE_E, alpha=0.7, label="Temples"),
    Line2D([0], [0], color=CANAL, linewidth=1.2, alpha=0.7, label="Waterways"),
]
ax.legend(
    handles=legend_elements,
    loc="lower right",
    facecolor=BG,
    edgecolor=LEGEND_E,
    labelcolor=TEXT,
    fontsize=9,
)

ax.set_title(
    "Angkor Archaeological Park — Barays, Temples, and Waterways",
    color=TEXT,
    fontsize=13,
    pad=12,
)
ax.tick_params(colors="#6a7870")
for spine in ax.spines.values():
    spine.set_edgecolor(SPINE)
    spine.set_alpha(0.35)

plt.tight_layout()
plt.show()

East and West Barays of Angkor with temple locations. Data: OpenStreetMap Overpass API.

The Island Temples

Each baray held a temple on an artificial island at its center. The cosmological logic was precise: the baray was the cosmic ocean, the island was Mount Meru, and the temple at the summit was the axis around which the Hindu universe turned. The king who built the baray and the temple was not merely a political ruler but a divine pivot.

East Mebon (953 CE)

Rajendravarman II consecrated the East Mebon in 953 CE, building in the Pre Rup architectural style: a multi-tiered sandstone pyramid with brick towers at each level and a quincunx of five towers at the summit. The structure rises 18 meters from a 120-meter square base. Eight three-headed elephant sculptures in sandstone anchor the corners of the lower two terraces — well-preserved and unique to this temple.

The East Mebon was once reached exclusively by boat. The baray it sat in is now dry, and the temple stands in open fields.

West Mebon (~1060 CE)

Udayadityavarman II built the West Mebon in the Baphuon and Kleang architectural style, contemporary with the Baphuon temple in Angkor Thom. The structure is largely ruined today: only laterite foundations and scattered sandstone fragments remain, and the central tower is entirely gone.

Its dedication to Vishnu was confirmed in 1936 by the discovery of a 5.9-meter bronze fragment of a colossal reclining Vishnu, one of the most significant Angkorian bronze sculptures ever recovered. The fragment is now in the National Museum of Cambodia in Phnom Penh. The West Mebon remains accessible only by boat across the still-full West Baray.

Show code
mebon_table = mebons[[
    "name", "baray", "consecration_year", "commissioning_king",
    "architectural_style", "religious_dedication",
    "base_dimension_m", "height_m", "preservation_status", "accessible_by"
]].copy()
mebon_table.columns = [
    "Temple", "Baray", "Consecrated", "Built by",
    "Style", "Dedicated to", "Base (m)", "Height (m)", "Status", "Access"
]
mebon_table
Temple Baray Consecrated Built by Style Dedicated to Base (m) Height (m) Status Access
0 East Mebon east_baray 953.0 Rajendravarman II Pre Rup style Shiva (Hindu) 120.0 18.0 Well-preserved foot
1 West Mebon west_baray NaN Udayadityavarman II Baphuon / Kleang style Vishnu (Hindu) 100.0 NaN Largely ruined - laterite foundations only boat

The Hydraulic City: Interactive Map

Show code
CENTER = [13.41, 103.87]

m = folium.Map(location=CENTER, zoom_start=12, tiles=None)

folium.TileLayer(
    tiles="CartoDB dark_matter",
    name="Dark (CartoDB)",
    control=True,
).add_to(m)

folium.TileLayer(
    tiles="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
    attr="Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community",
    name="Satellite (Esri)",
    control=True,
).add_to(m)

Fullscreen(position="topright").add_to(m)
MiniMap(tile_layer="CartoDB positron", position="bottomright", width=130, height=85,
        zoom_level_offset=-5, toggle_display=True).add_to(m)

# Waterways layer
ww_layer = folium.FeatureGroup(name="Canals and Waterways", show=True)
if not waterways.empty:
    folium.GeoJson(
        waterways.__geo_interface__,
        style_function=lambda f: {"color": "#3d7a9e", "weight": 1.2, "opacity": 0.6},
    ).add_to(ww_layer)
ww_layer.add_to(m)

# Barays layer
baray_layer = folium.FeatureGroup(name="Barays (Reservoirs)", show=True)
if not barays.empty:
    folium.GeoJson(
        barays.__geo_interface__,
        style_function=lambda f: {
            "fillColor": "#4a90c4", "color": "#6ab0e0",
            "weight": 1.5, "fillOpacity": 0.35,
        },
        tooltip=folium.GeoJsonTooltip(fields=["name"], aliases=["Baray:"]),
    ).add_to(baray_layer)
baray_layer.add_to(m)

# Temples layer
temple_layer = folium.FeatureGroup(name="Temples", show=True)
if not temples.empty:
    folium.GeoJson(
        temples.__geo_interface__,
        style_function=lambda f: {
            "fillColor": "#c9a84c", "color": "#e8c96c",
            "weight": 1.0, "fillOpacity": 0.45,
        },
        tooltip=folium.GeoJsonTooltip(fields=["name"], aliases=["Temple:"]),
    ).add_to(temple_layer)
temple_layer.add_to(m)

# Mebon point markers
mebon_layer = folium.FeatureGroup(name="Island Temples (Mebon)", show=True)
for _, row in mebons.iterrows():
    popup_html = f"""
    <div style='min-width:220px; font-family:serif;'>
        <b style='font-size:1.05em; color:#c9a84c;'>{row['name']}</b><br>
        <i style='color:#888;'>{row['architectural_style']}</i><br>
        <span style='color:#aaa;'>Consecrated: {row['consecration_year'] or 'c. 1060'} CE</span><br>
        <span style='color:#aaa;'>Built by: {row['commissioning_king']}</span><br>
        <span style='color:#aaa;'>Status: {row['preservation_status']}</span>
    </div>
    """
    folium.CircleMarker(
        location=[row.geom.y, row.geom.x],
        radius=9,
        color="#c9a84c",
        fill=True,
        fill_color="#c9a84c",
        fill_opacity=0.85,
        popup=folium.Popup(popup_html, max_width=280),
        tooltip=row["name"],
    ).add_to(mebon_layer)
mebon_layer.add_to(m)

folium.LayerControl().add_to(m)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

Angkor Wat’s Moat: Engineering in Detail

The moat encircling Angkor Wat measures approximately 1.5 kilometers by 1.3 kilometers, with a width of roughly 190 meters. Leveling a water surface across this area required surveying methods far beyond rope and stick. Khmer engineers used water-filled trenches and celestial sight lines to achieve consistent gradients across the full perimeter. The moat’s corners were rounded deliberately to improve water circulation and prevent stagnation at the edges. Its depth and slope were calibrated to regulate hydrostatic pressure against the temple’s foundations.

Some scholars describe Angkor Wat as a hydraulic pivot within the wider network. Positioned between northern and southern canal basins, the temple’s water infrastructure helped redistribute excess flow during monsoon peaks and sustained groundwater levels during the dry season. The canals surrounding it were engineered with precise gradients to move water smoothly, avoiding both stagnation and the erosive surges that silted other channels.

Inside the temple, drainage was equally deliberate. Subtle floor gradients directed monsoon rainfall away from structural areas. Concealed channels beneath carved stonework carried runoff from gallery floors. Modern restoration teams working at Angkor Wat frequently find that the most effective intervention is to re-enable original Khmer drainage features rather than introduce new systems. The original infrastructure, designed for this climate and these soils, continues to outperform alternatives.

Collapse of the Machine

Climate and the Killing Season

The hydraulic system that built the empire also contributed to its collapse. Paleoclimate data derived from tree-ring records shows that the 14th and 15th centuries brought a brutal alternation: extended droughts followed by catastrophic monsoon events. This pattern struck at the specific vulnerability of the Angkorian system. The canals and barays were engineered for a relatively predictable seasonal rhythm. They were not engineered for drought years that left the watershed bare, followed by intense rainfall events that flushed enormous sediment loads into the network.

In some areas, erosion cut channels 8 meters below the surrounding terrain. Key arteries silted shut. The system that had enabled three rice harvests per year ceased to function reliably, then in sections, then across whole districts.

What LiDAR Found

The Greater Angkor Project used airborne LiDAR (Light Detection and Ranging) technology to produce high-resolution topographic maps of the Angkor region beneath the forest canopy. The technology revealed a pre-industrial urban complex far larger than previously understood, along with the failure points of its hydraulic infrastructure.

Hydrological models built from the LiDAR data demonstrated how floods, after the network was compromised, concentrated into a diminishing number of functional channels. The concentration increased erosive force in those channels while reducing flow in others, accelerating silting. Each failure made the next more likely. The system collapsed not from a single blow but from cascading interdependence.

1431

By the time the Ayutthaya Kingdom sacked Angkor in 1431, the hydraulic machine had already fractured. The sack accelerated an abandonment already underway. The capital moved south to Lovek, then Phnom Penh. The jungle moved into the canal network. By the time French naturalist Henri Mouhot encountered Angkor Wat in 1860, the temple had been maintained by Buddhist monks in continuous occupation for four centuries, but the hydraulic city it once anchored was invisible under the canopy.

The LiDAR surveys have now made it visible again.

Site Status

Angkor was inscribed on the UNESCO World Heritage List in 1992, covering approximately 400 km² of temples, hydraulic infrastructure, and ancient urban fabric. It was briefly placed on the Danger List due to looting and uncontrolled development in the early post-conflict period, then removed in 2004 following sustained international conservation investment. The site receives approximately 2 million visitors per year and is managed by APSARA National Authority under the Cambodian government.

The West Baray remains functional as a reservoir. Farmers cultivate the bed of the East Baray. The canal network is partially traceable on the ground and in full detail in the LiDAR data. The mebons sit in the centers of their respective barays, one dry, one wet, as they have since the 11th century.

Modern Conservation

Since the 1990s the APSARA National Authority has worked with international conservation partners to restore key hydraulic features. The West Baray and the reflecting pool of Srah Srang have been rehabilitated to address water shortages and reduce flood risk in the Siem Reap region. The 12-kilometer moat surrounding Angkor Thom has also been renovated.

Groundwater beneath the temple foundations is now monitored continuously. The temples that have survived nine centuries did so because their soils remained consistently saturated. Over-extraction from surrounding communities risks introducing exactly the differential drying that Khmer engineers designed the moats to prevent. The hydraulic system that was built to sustain the city is now the mechanism by which the city sustains its temples.

geoglypha1.org