Postal Codes Dataset for Singapore, SG

489
Updated:
Files:1
Size:12 MB
Rows:121,513
Formats:csv

Postal Codes Dataset for Singapore, SG including name of the city, town, or place, various administrative divisions and alternative city names.

Part of a Data Solution

  • Postal Codes Solution

    Every worldwide postal-code dataset in one bundle — the ultimate global reference for precise postal codes.

    Explore →

Premium

You're viewing a free sample

Get the complete dataset — all rows and files — delivered instantly after checkout, with lifetime access to the latest version.

  • Secure checkout via Stripe
  • Instant download after payment
  • Lifetime access to the latest version
  • Singapore Open Data Licence version 1.0 license
20% off
$99.90$79.92
one-time payment

API Access

Access dataset files directly from scripts, code, or AI agents.

Browse dataset files
Dataset Files

Each file has a stable URL (r-link) that you can use directly in scripts, apps, or AI agents. These URLs are permanent and safe to hardcode.

/logistics/postal-codes-sg/
https://datahub.io/logistics/postal-codes-sg/_r/-/.licensing-notes.md
https://datahub.io/logistics/postal-codes-sg/_r/-/.migration-notes.md
https://datahub.io/logistics/postal-codes-sg/_r/-/ATTRIBUTION.txt
https://datahub.io/logistics/postal-codes-sg/_r/-/README.md
https://datahub.io/logistics/postal-codes-sg/_r/-/datapackage.yaml
Key Files

Start with these files — they give you everything you need to understand and access the dataset.

datapackage.yaml— metadata & schema
https://datahub.io/logistics/postal-codes-sg/_r/-/datapackage.yaml
README.md— documentation
https://datahub.io/logistics/postal-codes-sg/_r/-/README.md
Typical Usage
  1. 1. Fetch datapackage.yaml to inspect schema and resources
  2. 2. Download data resources listed in datapackage.yaml
  3. 3. Read README.md for full context

Data Files

postal-codes-sg-sample


About this dataset

Singapore (SG): migration notes

Internal record of the P5 migration from the old scripts to the producer: the discrepancies found, their causes, and who decided what. This is a dated record, so the numbers are as of the migration and not kept current. It is not shipped in the zip.

  • Issue: pc-28e.7.51 (closed 2026-10-03)
  • Commit: d62fae6 (worktree commit 55d0071, landed unchanged), batch 4
  • Parity verdict: format-only (CRLF → LF); passes the gate
  • Producer: custom, refresh disabled

Sources

InputURLNotes
OneMap (Singapore Land Authority) address dump, June 2020 snapshothttps://raw.githubusercontent.com/isen-ng/singapore-postal-codes-1/master/database.json.gzStatic file in a GitHub mirror (141,848 records). No OneMap API call, no crawl, no auth. Postal code, building, road name, coordinates
URA Master Plan 2019 Subzone Boundary (No Sea) GeoJSONhttps://api-open.data.gov.sg/v1/public/api/datasets/d_8594ae9ff96d0c708bc2af633048edfb/poll-downloaddata.gov.sg returns a signed S3 link, which the producer follows; the stable poll URL is recorded in sg.inputs.json

Both are under the Singapore Open Data Licence v1.0 (.licensing-notes.md).

  • The old pipeline didn't fetch anything. build_base.py read a staged export, sources/singapore_fedex_base.csv, produced by an external scraper (fedex-agents-prototype/countries/SGP/scripts/scrape_postal.py), and join_coordinates.py added coordinates from the OneMap dump. The scraper is no longer on this machine.
  • This is a plan D1 case (a dataset built from a missing intermediate export); the plan names the sg OneMap scrape explicitly. The agent rebuilt the scraper's steps from the two inputs above and checked them against the live zip cell for cell.

Parity against the live zip (2026-10-03)

Rows: 121,513 live and 121,513 fresh, none only on one side. 0 changed cells. With CRs stripped, the fresh CSV is byte-identical to the live one, row order included.

The public sample (postal.datahub.io/sg/sg.csv) came out unexplained (informational only); it wasn't investigated.

Decisions

DecisionByBasis
Reconstruct the missing scraper step from the original sources rather than hold sg backPlan decision D1; orchestrator instruction to stop and report if OneMap needed auth or a per-address crawlNeither was needed: the old pipeline only ever read the static June 2020 dump
Land without askingStanding rule (row_order/CRLF-only, user, 2026-10-02)format-only, equal rows, 0 changed cells
Keep admin_code2/3 empty, although the GeoJSON carries URA codes (PLN_AREA_C, e.g. BM; SUBZONE_C, e.g. BMSZ12)Agent: kept for parityFollow-up filed by the orchestrator as pc-7gv (P4)
Point-in-polygon in pure Python (even-odd ray casting, holes and multipolygons), no shapelyAgent
Remove the row, "zero duplicates" and per-tier row counts from READMEAgent, per the README counts ruleATTRIBUTION.txt untouched

Transforms carried over

Reconstructed from the scraper's documented behaviour plus build_base.py and join_coordinates.py (integrity_checker.py, package.py, publish_r2.py and the scripts README deleted):

  • For each postal code, the first OneMap record whose point falls inside a subzone polygon sets the place and admin columns. Codes with no such record, the "NIL" postal code and records without coordinates are dropped.
  • place_name = BUILDING, or ROAD_NAME when BUILDING is "NIL".
  • admin_name2 / admin_name3 = planning area / subzone, title-cased.
  • admin_name1 / admin_code1 = CDC district from the subzone's URA region: Central → Central Singapore 01, North-East → North East 02, North → North West 03, East → South East 04, West → South West 05.
  • Coordinates from the record whose BUILDING or ROAD_NAME equals place_name, rounded to 7 dp, blanked outside the bounding box. accuracy = BUILDING; alternative_city_name empty.
  • Rows ordered by district code, planning area, subzone, then dump order.
  • Old asserts are now ProducerErrors: known URA region, named subzones, readable inputs, all 5 CDC districts present. No row-count assert. Primary key postal_code.

Open questions

  • Resolved (user, 2026-10-05, pc-28e.7.59): keep the June 2020 OneMap snapshot (staleness disclosed). Evaluating the OneMap API is tracked as pc-5kk.1.
  • URA codes for admin_code2/3: open as pc-7gv.
  • .licensing-notes.md still describes the deleted scripts and carries counts (121,513 rows, 141,848 records); the README Fields table still has a "Fill" column with percentages. Left for the end-of-epic sweep (pc-hfz).

Provenance

Reconstructed 2026-10-05 from the agent transcript d33e1b7e-5027-498a-a97f-ba914ee2524e/subagents/agent-a7a0b891bb088f0a5.jsonl, the orchestrator session d33e1b7e-… (launch instruction, landing, pc-7gv), the plan's D1 entry (session 068ca403-…), the commit message, the bd close reason and docs/parity/p5.md.