Does your town have a tower?
Pick your HDB town to see its tallest block, how many blocks tie for the top, and whether it has a block of 30 floors or more. HDB data, updated Jul 2026.
How tall is the tallest block in my town?
Each building is the tallest block in one town, from the tallest town on the left to the lowest on the right. More floors means a taller building. Hover a building for details and click to pick it. On a phone, tap once for details and tap again to pick it.
The tallest HDB block in Singapore has 50 floors. The lowest top block in any town has 16.
Is it one block, or a tie?
Each small building is one block that reaches the top height in your town. Hover or tap one for its address and year.
Only 3 of the 27 towns have a single tallest block: Bukit Panjang, Woodlands and Bukit Timah.
Does my town have a tower?
We call a block of 30 floors or more a tower. Each bar is the number of towers in one town, and your town is in red. Hover a bar for details and click to pick it. On a phone, tap once for details and tap again to pick it.
Bukit Merah, Queenstown, Toa Payoh, Kallang/Whampoa and Clementi hold 7 in 10 of the 342 blocks of 30 floors or more.
When did my town get its tallest block?
Each building is the tallest block your town finished in that decade, with heights scaled to your town's top, so you can compare decades within your town. The small number under each decade is how many blocks were finished. The red one is where your town first reached its top height. Hover or tap a building for details.
Fun finds
The short version
Only 13 of Singapore's 27 HDB towns have a block of 30 floors or more, and 7 in 10 of the 342 such blocks are in just five towns; the tallest HDB block has 50 floors, and 7 blocks tie for it.
What we did. We took HDB's property file on data.gov.sg, which lists every building with its top floor and the year it was completed, and kept the 10,796 residential blocks (blocks with homes in them). For each of the 27 HDB towns we found the highest floor count, counted how many blocks share it, and counted blocks of 30 floors or more.
What we found. The tallest block has 50 floors: blocks 1A to 1G Cantonment Road in the Central Area, all completed in 2009. Bukit Merah comes next at 48 floors. In 24 of the 27 towns more than one block shares the top height, so "the tallest block" is a single block in only 3 towns. 14 towns have no block of 30 floors or more, including Sengkang (27 floors at the top), Punggol (26) and Tampines (17), while Bukit Merah, Queenstown, Toa Payoh, Kallang/Whampoa and Clementi hold 241 of the 342. 92% of the 30-floor-plus blocks were completed in 2000 or later.
What to keep in mind. Floors are counted as HDB lists them, not measured in metres, and 30 floors is our own round-number line for a tower, not an HDB term. The towns are HDB's own, which are not the same as URA planning areas. Only HDB blocks are counted, so private condominiums are left out. We show what the file says, not why towns look the way they do.
By Ben (opens in a new tab). Updated . Data: HDB, HDB Property Information, data.gov.sg.
Questions people ask
What is the tallest HDB block in Singapore?
In HDB's property file, the tallest blocks have 50 floors. There are 7 of them, blocks 1A to 1G Cantonment Road in the Central Area, all completed in 2009. The next tallest are 95C and 96A Henderson Road in Bukit Merah, at 48 floors.
Which HDB town has the tallest block?
The Central Area, with 50 floors. It is followed by Bukit Merah (48), Queenstown (47) and Toa Payoh (42).
How many HDB blocks have 30 floors or more?
342 of the 10,796 residential blocks, about 1 in 32. 13 of the 27 towns have at least one. Bukit Merah, Queenstown, Toa Payoh, Kallang/Whampoa and Clementi hold 241 of them between them.
Which HDB towns have no block of 30 floors or more?
Bedok, Bukit Timah, Geylang, Hougang, Jurong West, Marine Parade, Pasir Ris, Punggol, Sembawang, Sengkang, Serangoon, Tampines, Tengah and Yishun. The tallest block in each of them has between 16 and 27 floors.
Why do so many blocks tie for the tallest in their town?
In 24 of the 27 towns, more than one block reaches the top height. In 10 of those 24, the tied blocks were all completed in the same year. The extreme is Tampines, where 44 blocks tie at 17 floors. Only Bukit Panjang, Woodlands and Bukit Timah have a single tallest block. This page shows the tie, and names the blocks, instead of picking one.
How many floors does a typical HDB block have?
The middle block has 13 floors, and the most common height is 12: 1,953 of the 10,796 blocks, nearly 1 in 5, have exactly 12 floors.
When were HDB blocks of 30 floors or more built?
Mostly recently: 316 of the 342 (92%) were completed in 2000 or later. No block completed before 1990 has more than 27 floors.
Is the tallest block in a town also its newest?
Not always. In Bedok, Bukit Timah, Geylang, Jurong West and Marine Parade, the tallest blocks were completed between 1974 and 1982, and no block finished since is taller.
What do "floors" mean on this page?
The highest floor level HDB lists for the block ("Max Floor Lvl" in its file). We have not turned it into metres.
Does this cover every HDB block?
It covers the 10,796 blocks in the file that are marked residential and have at least one home. The file has 13,357 records in all; the other 2,561 are buildings that are not residential, such as carparks and shops. Private condominiums are not HDB blocks, so they are not here.
How up to date is it?
HDB last updated the file on 6 Jul 2026, and we downloaded it on 7 Oct 2026. 56 blocks list 2026 as their completion year, and we count them as listed.
The numbers behind it
| Town | Residential blocks | Tallest block (floors) | Blocks at that height | Completed | Middle block (floors) | Blocks of 30+ floors |
|---|---|---|---|---|---|---|
| Central Area | 79 | 50 | 7 | 2009 | 19 | 7 |
| Bukit Merah | 426 | 48 | 2 | 2018 | 14 | 75 |
| Queenstown | 242 | 47 | 9 | 2015 to 2021 | 16 | 61 |
| Toa Payoh | 386 | 42 | 2 | 2012 | 14 | 41 |
| Bishan | 238 | 40 | 3 | 2011 | 12.5 | 13 |
| Bukit Batok | 435 | 40 | 3 | 2017 | 12 | 14 |
| Clementi | 206 | 40 | 21 | 2010 to 2023 | 12 | 29 |
| Jurong East | 234 | 40 | 4 | 2012 | 13 | 9 |
| Kallang/Whampoa | 312 | 40 | 9 | 2011 to 2026 | 15 | 35 |
| Bukit Panjang | 346 | 38 | 1 | 2022 | 15 | 20 |
| Ang Mo Kio | 392 | 34 | 2 | 2017 | 12 | 20 |
| Woodlands | 741 | 33 | 1 | 2015 | 12 | 16 |
| Choa Chu Kang | 529 | 31 | 2 | 2023 | 14 | 2 |
| Sengkang | 669 | 27 | 8 | 2010 to 2013 | 16 | 0 |
| Punggol | 557 | 26 | 14 | 2020 to 2025 | 17 | 0 |
| Bedok | 530 | 25 | 25 | 1974 to 1979 | 13 | 0 |
| Geylang | 310 | 25 | 2 | 1976 | 12 | 0 |
| Jurong West | 744 | 25 | 6 | 1978 to 1982 | 15 | 0 |
| Marine Parade | 59 | 25 | 17 | 1974 to 1976 | 16 | 0 |
| Bukit Timah | 27 | 23 | 1 | 1974 | 13 | 0 |
| Sembawang | 281 | 23 | 2 | 2013 | 15 | 0 |
| Hougang | 610 | 20 | 4 | 1975 to 2013 | 13 | 0 |
| Pasir Ris | 441 | 18 | 14 | 1993 to 2025 | 13 | 0 |
| Tampines | 924 | 17 | 44 | 2009 to 2026 | 12 | 0 |
| Serangoon | 232 | 16 | 13 | 1984 to 2016 | 12 | 0 |
| Tengah | 139 | 16 | 10 | 2024 to 2026 | 14 | 0 |
| Yishun | 707 | 16 | 13 | 1985 to 2013 | 12 | 0 |
| Town | Before 1970 | 1970s | 1980s | 1990s | 2000s | 2010s | 2020s |
|---|---|---|---|---|---|---|---|
| Central Area | 20 (13) | 27 (31) | 25 (24) | none | 50 (11) | none | none |
| Bukit Merah | 16 (110) | 25 (123) | 25 (56) | 30 (41) | 30 (59) | 48 (37) | none |
| Queenstown | 16 (77) | 25 (63) | none | 30 (34) | 40 (16) | 47 (35) | 47 (17) |
| Toa Payoh | 20 (69) | 25 (71) | 23 (80) | 30 (52) | 40 (12) | 42 (23) | 40 (79) |
| Bishan | none | 12 (4) | 26 (140) | 30 (81) | none | 40 (5) | 39 (8) |
| Bukit Batok | none | none | 25 (283) | 25 (49) | 30 (16) | 40 (69) | 28 (18) |
| Clementi | none | 25 (106) | 25 (51) | none | 25 (11) | 40 (23) | 40 (15) |
| Jurong East | none | 25 (28) | 25 (147) | 25 (37) | 25 (6) | 40 (13) | 37 (3) |
| Kallang/Whampoa | 16 (54) | 25 (94) | 27 (76) | 28 (31) | 30 (17) | 40 (27) | 40 (13) |
| Bukit Panjang | none | none | 21 (155) | 30 (86) | 30 (52) | 34 (45) | 38 (8) |
| Ang Mo Kio | none | 25 (268) | 25 (67) | 30 (17) | 28 (11) | 34 (21) | 29 (8) |
| Woodlands | none | 25 (34) | 25 (188) | 14 (369) | 16 (32) | 33 (83) | 32 (35) |
| Choa Chu Kang | none | 25 (11) | 25 (72) | 22 (333) | 24 (31) | 24 (75) | 31 (7) |
| Sengkang | none | none | none | 17 (222) | 26 (196) | 27 (203) | 25 (48) |
| Punggol | none | none | none | none | 19 (186) | 22 (284) | 26 (87) |
| Bedok | none | 25 (232) | 18 (164) | 24 (78) | 20 (16) | 19 (26) | 18 (14) |
| Geylang | 16 (57) | 25 (65) | 21 (101) | 20 (21) | 19 (11) | 19 (17) | 19 (38) |
| Jurong West | none | 25 (47) | 25 (233) | 21 (291) | 20 (102) | 22 (59) | 18 (12) |
| Marine Parade | none | 25 (59) | none | none | none | none | none |
| Bukit Timah | none | 23 (7) | 15 (19) | none | none | 13 (1) | none |
| Sembawang | none | none | none | 16 (121) | 21 (52) | 23 (81) | 13 (27) |
| Hougang | none | 20 (15) | 19 (309) | 19 (178) | 18 (19) | 20 (69) | 19 (20) |
| Pasir Ris | none | 4 (3) | 13 (77) | 18 (328) | none | 14 (23) | 18 (10) |
| Tampines | none | none | 16 (468) | 16 (229) | 17 (9) | 17 (88) | 17 (130) |
| Serangoon | none | 14 (8) | 16 (157) | 16 (64) | none | 16 (3) | none |
| Tengah | none | none | none | none | none | none | 16 (139) |
| Yishun | none | 4 (1) | 16 (474) | 16 (24) | 15 (4) | 16 (146) | 15 (58) |
| Floors | Town | Street | Blocks | Completed |
|---|---|---|---|---|
| 50 | Central Area | Cantonment Road | 1A, 1B, 1C, 1D, 1E, 1F, 1G | 2009 |
| 48 | Bukit Merah | Henderson Road | 95C, 96A | 2018 |
| 47 | Queenstown | Margaret Drive | 30, 32, 33, 34, 36, 37 | 2021 |
| 47 | Queenstown | Dawson Road | 86, 87, 88 | 2015 |
| 45 | Queenstown | Margaret Drive | 39A, 40A, 42A, 43A | 2021 |
| 43 | Queenstown | Dawson Road | 89, 90, 91, 92, 93 | 2015 |
| 43 | Queenstown | Dawson Road | 94, 96 | 2020 |
| 43 | Queenstown | Strathmore Avenue | 53 | 2019 |
| Completed | Blocks | Tallest (floors) | Blocks of 30+ floors |
|---|---|---|---|
| Before 1970 | 380 | 20 | 0 |
| 1970s | 1,270 | 27 | 0 |
| 1980s | 3,341 | 27 | 0 |
| 1990s | 2,686 | 30 | 26 |
| 2000s | 869 | 50 | 93 |
| 2010s | 1,456 | 48 | 154 |
| 2020s | 794 | 47 | 69 |
The boring bit
Where the data comes from
HDB's HDB Property Information file on data.gov.sg, last updated by HDB on 6 Jul 2026 and downloaded on 7 Oct 2026. It lists 13,357 buildings with their highest floor, completion year, town and number of homes. We kept the 10,796 that are marked residential and have at least one home. Towns are the 27 HDB towns in the file's own town column.
What is not claimed
- Floors are the number HDB lists as a block's highest floor level, not a height in metres.
- 30 floors as the line for a tower is our own round number, not an HDB term. At 40 floors, 9 towns have a block and the five biggest hold 86% of the 121; at 25 floors, 19 towns have one and the five biggest hold 51% of the 833.
- Counts of towers are not adjusted for how many blocks a town has. Hover a bar to see "1 in N" for that town. Towns with fewer than 100 residential blocks are Bukit Timah (27 blocks), Marine Parade (59 blocks) and Central Area (79 blocks); we show them, and the page marks them as small towns, because their counts rest on few blocks.
- HDB towns are not the same as the planning areas used on our rain page, so a town's name can cover a different patch of ground.
- Only HDB blocks are counted. Private condominiums, which can be taller, are not in this file.
- The file says its dates run to 31 Dec 2025, yet 56 blocks list 2026 as their completion year. We use the file as published.
- Decades use the completion year in the file. "Before 1970" groups the earliest blocks, and a decade with no blocks in a town is shown as none.
- When blocks tie we show all of them. We never pick one, and we do not call any town or block better or worse.
- We do not say why some towns have towers and others do not. The file shows what was built, not why.
Coverage
10,796 residential blocks in 27 towns, from 27 blocks in Bukit Timah to 924 in Tampines. The skyline shows each town's top block, so every town has one building whatever its size.
Report an error. Corrections are logged publicly with a date.
How we did it
- Downloaded HDB's property file from data.gov.sg on 7 Oct 2026: 13,357 records, one for each building.
- Kept the homes. A record stays if it is marked residential and has at least one home: 10,796 blocks. The other 2,561 records, such as carparks and shops, are left out.
- Named the towns from the legend in HDB's own description of the town column (for example CT is Central Area, KWN is Kallang/Whampoa).
- Found each town's top. The highest floor count in the town, then every block that has it, with its street and completion year.
- Counted blocks of 30 floors or more in each town and in all of Singapore, and grouped each town's blocks by the decade they were completed.
- Counted twice. The prep script counts the headline numbers with pandas and the page counts them again with plain Python; the build stops if any town's block count, tallest height, blocks at the top or blocks of 30+ floors differs.
Show the Python code
"""Rebuilds this insight's data files from HDB's public file.
python prep/prep_tower.py download HDB Property Information from data.gov.sg, then rebuild
python prep/prep_tower.py path.csv rebuild from a file you already have (no download)
Writes (next to this folder, in data/):
raw/HDBPropertyInformation.csv the file exactly as downloaded (only when downloading)
dataset_metadata.json data.gov.sg's own record of the file (name, last updated, coverage end)
hdb_blocks.csv the residential blocks the page uses: one row per block
prep_numbers.json the headline numbers, counted here with pandas (the page counts them again
with plain Python; build_page.py asserts the two agree)
Rule for "residential": the file's residential flag is Y and the block has at least one home.
"""
import csv, json, sys, urllib.request, time
from pathlib import Path
import pandas as pd
HERE = Path(__file__).resolve().parent
DATA = HERE.parent / "data"
DATASET = "d_17f5382f26140b1fdae0ba2ef6239d2f"
API = "https://api-open.data.gov.sg/v1/public/api/datasets/" + DATASET + "/poll-download"
META = "https://api-production.data.gov.sg/v2/public/api/datasets/" + DATASET + "/metadata"
# Town codes, from the legend in HDB's own description of the town column (data.gov.sg metadata)
TOWNS = {"AMK": "Ang Mo Kio", "BB": "Bukit Batok", "BD": "Bedok", "BH": "Bishan", "BM": "Bukit Merah",
"BP": "Bukit Panjang", "BT": "Bukit Timah", "CCK": "Choa Chu Kang", "CL": "Clementi",
"CT": "Central Area", "GL": "Geylang", "HG": "Hougang", "JE": "Jurong East", "JW": "Jurong West",
"KWN": "Kallang/Whampoa", "MP": "Marine Parade", "PG": "Punggol", "PRC": "Pasir Ris",
"QT": "Queenstown", "SB": "Sembawang", "SGN": "Serangoon", "SK": "Sengkang", "TAP": "Tampines",
"TG": "Tengah", "TP": "Toa Payoh", "WL": "Woodlands", "YS": "Yishun"}
TOWER = 30
def get(url):
# data.gov.sg refuses requests that carry no User-Agent (HTTP 403), so send a plain one
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0 (CompareSG insight prep)"})
with urllib.request.urlopen(req, timeout=60) as r:
return r.read()
def download():
meta = json.loads(get(META))["data"]
keep = {k: meta[k] for k in ("datasetId", "name", "managedBy", "lastUpdatedAt", "coverageStart", "coverageEnd", "format")}
(DATA / "dataset_metadata.json").write_text(json.dumps(keep, indent=1), encoding="utf-8")
for _ in range(10):
j = json.loads(get(API))["data"]
if j.get("status") == "DOWNLOAD_SUCCESS":
break
time.sleep(3)
raw = get(j["url"])
(DATA / "raw").mkdir(exist_ok=True)
p = DATA / "raw" / "HDBPropertyInformation.csv"
p.write_bytes(raw)
return p
def main():
src = Path(sys.argv[1]) if len(sys.argv) > 1 else download()
d = pd.read_csv(src)
r = d[(d.residential == "Y") & (d.total_dwelling_units > 0)].copy()
assert r.bldg_contract_town.isin(TOWNS).all(), "a town code is missing from the legend"
r = r.sort_values(["bldg_contract_town", "street", "blk_no"], kind="mergesort")
with open(DATA / "hdb_blocks.csv", "w", newline="", encoding="utf-8") as f:
w = csv.writer(f, lineterminator="\n")
w.writerow(["blk_no", "street", "town_code", "max_floor_lvl", "year_completed", "total_dwelling_units"])
for b in r.itertuples():
w.writerow([b.blk_no, b.street, b.bldg_contract_town, int(b.max_floor_lvl), int(b.year_completed), int(b.total_dwelling_units)])
towns = {}
for code, x in r.groupby("bldg_contract_town"):
top = x[x.max_floor_lvl == x.max_floor_lvl.max()]
towns[TOWNS[code]] = dict(blocks=len(x), tallest=int(x.max_floor_lvl.max()), at_top=len(top),
first_done=int(top.year_completed.min()), last_done=int(top.year_completed.max()),
towers=int((x.max_floor_lvl >= TOWER).sum()))
out = dict(records=len(d), residential=len(r), towers=int((r.max_floor_lvl >= TOWER).sum()),
towns_with_towers=sum(1 for v in towns.values() if v["towers"] > 0),
at_40_plus=int((r.max_floor_lvl >= 40).sum()), exactly_12=int((r.max_floor_lvl == 12).sum()),
completed_2026=int((r.year_completed == 2026).sum()), towns=towns)
(DATA / "prep_numbers.json").write_text(json.dumps(out, indent=1, sort_keys=True), encoding="utf-8")
print("records", len(d), "residential", len(r), "towers", out["towers"], "wrote", DATA / "hdb_blocks.csv")
if __name__ == "__main__":
main()
What could make it wrong: a floor count or year that is wrong in the file, a block listed under a different town from the one people call it, or the choice of 30 floors as the line. The two separate counts agree on every town, so the counting is not the weak point; the file is.
No machine learning was needed. The questions were "how tall" and "how many", which sorting and counting answer directly.
Source: HDB, HDB Property Information (opens in a new tab), data.gov.sg, downloaded 7 Oct 2026. Contains information from data.gov.sg made available under the Singapore Open Data Licence.