{"id":27726,"date":"2025-02-23T20:04:08","date_gmt":"2025-02-23T18:04:08","guid":{"rendered":"https:\/\/www.geopostcodes.com\/en-GB\/?p=27726"},"modified":"2026-04-01T07:01:01","modified_gmt":"2026-04-01T07:01:01","slug":"postal-code-polygon-database","status":"publish","type":"post","link":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/","title":{"rendered":"How to Build a Postcode Polygon Database"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Key Takeaways<\/h2>\n\n\n\n<div style=\"height:40px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Postcode polygons enable georeferencing for BI, sales, and spatial analysis<\/li>\n\n\n\n<li>Build polygons using postal data or create from geocoded points<\/li>\n\n\n\n<li>Align boundaries with administrative divisions for better accuracy<\/li>\n\n\n\n<li>Handle multi-postcode municipalities by subdividing with Voronoi methods<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p>Because postcodes are generally the most granular geographic unit that is easily obtainable, organizations often use them as data points for location-specific decisions, such as whether to open a new warehouse or close a store.<\/p>\n\n\n\n<p>Postcodes can be spatially represented through a pair of coordinates (latitude and longitude) to approximate their center. However, as the areas they cover vary in shape and size, such representations fall short of exhibiting their actual extents and relationships\u2014such as information on neighboring postcodes or links with other geospatial data.<\/p>\n\n\n\n<p>For some applications, visually defining the boundaries of a postcode using a<a href=\"https:\/\/www.geopostcodes.com\/en-GB\/boundaries-database\/\" target=\"_blank\" rel=\"noreferrer noopener\">&nbsp;<u>polygon database<\/u><\/a>&nbsp;is critical. It offers a geographical representation of a territory that lets you georeference a dataset much more accurately. Postcode polygon databases are especially useful for BI maps, territory mapping, spatial analysis, and reverse geocoding.<\/p>\n\n\n\n<p>\ud83d\udca1 Use accurate&nbsp;<a href=\"https:\/\/www.geopostcodes.com\/en-GB\/postal-zip-code-database\/\" target=\"_blank\" rel=\"noreferrer noopener\">international postcode data<\/a>&nbsp;to build a postcode polygon database. Our location data is updated weekly, relying on more than 1,500 sources. Browse GeoPostcodes datasets and&nbsp;<strong><a href=\"https:\/\/public.geopostcodes.com\/portal-signup\" target=\"_blank\" rel=\"noreferrer noopener\">download a free sample here<\/a>.<\/strong><\/p>\n\n\n\n<p>This article shows you how to build a postal polygon database. You will learn how to translate point data into polygons using Voronoi polygons and increase accuracy by using the finest administrative divisions.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"toc-h2-1\">What Is a Postcode Polygon Database and When to Use It<\/h2>\n\n\n\n<p>A polygon is a two-dimensional geographical representation that defines the exterior boundary or area of something using a sequence of points and lines. They are often used to show the boundaries of cities or buildings on maps.<\/p>\n\n\n\n<p>A<a href=\"https:\/\/www.geopostcodes.com\/en-GB\/boundaries-database\/\" target=\"_blank\" rel=\"noreferrer noopener\">&nbsp;<u>postcode polygon database<\/u><\/a>&nbsp;is a database of such geographical representations based on postcode data. They show the geographical limits of the postcodes within a territory.<\/p>\n\n\n\n<p>In addition to helping users find postcodes within a certain area or showing the boundaries of postcodes, a postcode polygon database is useful for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>BI reporting<\/strong>: For instance, you can build a map that highlights your performance per postcode to inform marketing or optimize your store locations.<\/li>\n\n\n\n<li><strong>Managing sales or delivery territories<\/strong>: You can easily visualize the areas covered by each postcode, link them to the volume of service, and create relevant area groupings to optimize the capacity of your units, whether they are trucks, cargo bikes, or salespeople.<\/li>\n\n\n\n<li><strong>Spatial analysis<\/strong>: It lets you relate postcodes to other spatial features such as factories, shops, parks, water bodies, and so forth. For instance, it can help assess insurance risk in relation to the distance to the sea or some other feature.<\/li>\n\n\n\n<li><strong>Reverse geocoding<\/strong>: Refers to inferring postcodes from coordinates or GPS data. It lets you cross-reference other data sources at the postal level, and it can be used, for example, to trigger an automatic message when a customer signs up in a certain postcode area. Learn<a href=\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postcode-to-coordinates-converter\/\" target=\"_blank\" rel=\"noreferrer noopener\">&nbsp;<u>how to build a postcode to coordinates converter here<\/u><\/a>.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"toc-h2-2\">How to Build a Postcode Polygon Database<\/h2>\n\n\n\n<p>This article covers two ways to construct a postcode polygons database: when a good source for postcode polygon data is readily available, as well as when you only have access to underlying data in the form of points\u2014typically, addresses or postcode&nbsp;<a href=\"https:\/\/en.wikipedia.org\/wiki\/Centroid\" target=\"_blank\" rel=\"noreferrer noopener\">centroids.<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"toc-h3-0\">Prerequisites<\/h3>\n\n\n\n<p>To follow along with this article, you need:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>GIS software to visualize geographical data. This article uses the free, open-source system&nbsp;<a href=\"https:\/\/qgis.org\/en\/site\" target=\"_blank\" rel=\"noreferrer noopener\">QGIS<\/a>.<\/li>\n\n\n\n<li>SQL knowledge. This article uses SQL to process the data and some PostgreSQL extensions: PostGIS for geographic functions and PL\/pgSQL as a procedural programming language.<\/li>\n<\/ul>\n\n\n\n<p>Since you will be working with maps, some geographical knowledge is a plus.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"toc-h3-1\">Method 1: Using Postal Code Polygons from a Source<\/h3>\n\n\n\n<p>In some cases, you might be able to obtain polygons with the postal information you need from reliable sources.<\/p>\n\n\n\n<p>The most common sources are open data initiatives of certain countries\u2019 geographic institutes or postal systems. For example, the Geoportal of Belgian\u2019s federal government has a&nbsp;<a href=\"https:\/\/www.geo.be\/catalog\/details\/9738c7c0-5255-11ea-8895-34e12d0f0423?l=en\" target=\"_blank\" rel=\"noreferrer noopener\">free database of postal polygons from the national postal service in Shapefile format<\/a>. Many collaborative initiatives, like OpenStreetMap, also publish postal polygons in some areas.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/C6Mg7eQ.png\" alt=\"OpenStreetMap Screenshot\" \/><\/figure>\n\n\n\n<p>Where postal polygons are readily available, the steps are straightforward: you only need to find the source, make sure you respect its license terms and integrate it into your data.<\/p>\n\n\n\n<p>However, these sources may not be perfect or up-to-date. Even if you can access readily available postal boundary data, you\u2019ll therefore need to consider its quality and whether you can risk sacrificing accuracy and completeness for convenience. For instance, the Belgian postal boundaries omit some postal enclaves. Using high-quality geocoded points, as you\u2019ll learn how to do in the next section, can help refine the boundaries.<\/p>\n\n\n\n<p>\ud83d\udca1 Discover postal and administrative boundaries for 247 countries. Our location data is updated weekly, relying on more than 1,500 sources. <a href=\"https:\/\/public.geopostcodes.com\/map-explorer-portal-signup\"><strong>Browse our database for free here.<\/strong><\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"toc-h3-2\">Method 2: Building Polygons using Point Data<\/h3>\n\n\n\n<p>If you do not have a direct source of postal polygons or if it\u2019s not accurate or complete enough, you can build your own polygons from other data.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"sourcing-postal-points\">Sourcing Postcode Points<\/h4>\n\n\n\n<p>The first thing you need to find is a high-quality source of geocoded points that contain information on postal codes.<\/p>\n\n\n\n<p>This article uses the&nbsp;National Address Base of France with good-quality, open data. This database offers useful information, like street names, house numbers, postal codes, municipality names, and coordinates.<\/p>\n\n\n\n<p>To generate the postal code polygon for this tutorial, you\u2019ll use the coordinates (longitude and latitude) and postal codes from this database.<\/p>\n\n\n\n<p>Start by downloading the data from the&nbsp;<a href=\"https:\/\/adresse.data.gouv.fr\/data\/ban\/adresses\/latest\/csv\/\" target=\"_blank\" rel=\"noreferrer noopener\">National Address Base of France<\/a>. Select the&nbsp;<code>adresses-france.csv.gz<\/code>&nbsp;file, found roughly in the middle of the list of files, to get data for the whole country.<\/p>\n\n\n\n<p>Next, upload the CSV to a PostgreSQL database in a table called zips.source_points. Most SQL clients, such as PgAdmin and DBeavers, offer functionalities to upload a CSV directly from the graphical interface.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img fetchpriority=\"high\" decoding=\"async\" width=\"894\" height=\"153\" src=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/04\/TABLE.png\" alt=\"Screenshot of French address database\" class=\"wp-image-4497\" srcset=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/04\/TABLE.png 894w, https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/04\/TABLE-300x51.png 300w, https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/04\/TABLE-768x131.png 768w\" sizes=\"(max-width: 894px) 100vw, 894px\" \/><\/figure>\n\n\n\n<p>To process geospatial data, we will leverage the PostGIS extension of PostgreSQL. You can simply activate it by executing CREATE EXTENSION postgis; in a psql prompt.<\/p>\n\n\n\n<p>Now, you can convert the coordinates in zips.source_points to geometry objects with the following queries:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"postgresql\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ALTER TABLE zips.source_points ADD COLUMN geom geometry(Point,3857);\n\nUPDATE zips.source_points SET geom = ST_Transform(ST_SetSRID(ST_MakePoint(long, lat), 4326),3857);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"estimating-postal-boundaries-with-voronoi-polygons\">Estimating Postcode Boundaries with Voronoi Polygons<\/h4>\n\n\n\n<p>Next, you\u2019ll use the geocoded addresses you obtained in the previous step to build Voronoi polygons representing postal boundaries.<\/p>\n\n\n\n<p>First, what is a&nbsp;<a href=\"https:\/\/en.wikipedia.org\/wiki\/Voronoi_diagram\" target=\"_blank\" rel=\"noreferrer noopener\">Voronoi tessellation<\/a>? It\u2019s a partition of a space into multiple polygons based on point distribution. Points are considered&nbsp;<em>seeds<\/em>, and the linear delimitations of the Voronoi diagram are points that are equidistant to the two nearest seeds. A Voronoi&nbsp;<em>cell<\/em>&nbsp;consists of all points of the space that are closer to that seed than any other.<\/p>\n\n\n\n<p>The image below illustrates the equidistance of a Voronoi diagram with seeds in blue and tessellations in red.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/ItGlm0V.png\" alt=\"Voronoi seeds and tessellations, courtesy of [PostGIS](https:\/\/postgis.net\/docs\/ST_VoronoiPolygons.html)\" \/><\/figure>\n\n\n\n<p><a href=\"https:\/\/postgis.net\/docs\/ST_VoronoiPolygons.html\" target=\"_blank\" rel=\"noreferrer noopener\">Voronoi polygons<\/a>&nbsp;are a powerful tool for understanding and analyzing spatial data. They provide a way to divide a plane into regions based on the distances to a set of points, allowing for a polygonal representation of the underlying punctual data. Since the database you\u2019re using has multiple addresses for the same postal code, you\u2019ll obtain numerous Voronoi cells for each postal code. To build the postal polygons, you\u2019ll merge the Voronoi polygons corresponding to the same postal code.<\/p>\n\n\n\n<p>To generate Voronoi polygons in PostGIS\u2014the geographical data processing extension of PostgreSQL\u2014you\u2019ll use the&nbsp;<code>ST_VoronoiPolygons<\/code>&nbsp;function. Three parameters are needed: the geometry of the source of points; the tolerance (<em>ie<\/em>, the distance within which vertices will be considered equivalent); and the geographical extent (<em>ie<\/em>, territory) you want to cover. The signature of the function is:<\/p>\n\n\n\n<p><code>ST_VoronoiPolygons( g1 geometry , tolerance float8 , extend_to geometry );<\/code><\/p>\n\n\n\n<p>You are going to call that function from a PL\/pgSQL script handling all the other steps. PL\/pgSQL lets you write functions and procedures that are stored and executed within the database, making it easier to write complex and efficient queries. It combines SQL\u2019s simplicity and ease of use with the power and flexibility of more traditional programming languages.<\/p>\n\n\n\n<p>Consider this example PL\/pgSQL function,&nbsp;<code>zips.voronoi_geom()<\/code>:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"postgresql\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">CREATE OR REPLACE FUNCTION zips.voronoi_geom(p_geom geometry)\nRETURNS void\nLANGUAGE plpgsql\nAS $function$\nDECLARE\n\n\nbegin\n\n\n   --\n   -- SETUP\n   --\n\n\n   DROP TABLE IF EXISTS zips.voronoi;\n   CREATE TABLE IF NOT EXISTS zips.voronoi(\n       gid serial4 NOT NULL,\n       postcode varchar(20) NULL,\n       geom public.geometry(multipolygon, 3857) NULL\n   );\n   CREATE INDEX IF NOT EXISTS zips_voronoi_sidx ON zips.voronoi USING gist (geom);\n\n   CREATE TABLE IF NOT EXISTS zips.voronoi_pts (\n       postcode varchar(20) NULL,\n       geom public.geometry(point, 3857) NULL\n   );\n   CREATE INDEX IF NOT EXISTS zips_voronoi_pts_sidx ON zips.voronoi_pts USING gist (geom);\n\n\n   -- SELECT VORONOI POINTS (seeds) from the target geometry p_geom\n\n   TRUNCATE TABLE zips.voronoi_pts;\n\n\n   INSERT INTO zips.voronoi_pts(zip, geom)\n     SELECT pt.code_postal, pt.geom\n     FROM zips.source_points pt\n     WHERE ST_Contains(p_geom, pt.geom);\n\n\n   -- CREATE VORONOI polygons\n\n\n   TRUNCATE TABLE zips.voronoi;\n\n\n   INSERT INTO zips.voronoi(geom)\n     SELECT ST_Multi(ST_Intersection((ST_Dump(geom)).geom, p_geom)) FROM (\n       SELECT ST_CollectionExtract(ST_VoronoiPolygons(geom, 0.0, p_geom), 3) as geom\n       FROM (SELECT ST_Collect(geom) AS geom FROM zips.voronoi_pts) p\n     ) polys;\n\n\n    -- label Voronoi polygons with corresponding postcodes from the points data\n    UPDATE zips.voronoi a set postcode = p.zip\n    FROM zips.voronoi_pts p\n    WHERE ST_Contains(a.geom, p.geom);\n\n\nEND;\n$function$\n;<\/pre>\n\n\n\n<p>It first creates the tables that will be used in the rest of the function. It sets up \u2018zips.voronoi\u2019 to store the geometry polygon results and \u2018zips.voronoi_pts\u2019 to store a subset of the geocoded postal codes. In this example, this is the geocoded addresses in France from&nbsp;<code>zips.source_points<\/code>. You could also adapt this code to whatever area you\u2019re interested in, which can be smaller than an entire country.<\/p>\n\n\n\n<p>It also creates indexes for these tables on the geometry using GiST to speed up your processes.<\/p>\n\n\n\n<p>The body of the function is responsible for filling the `zips.voronoi_pts\u2019 table with the geocoded postal codes belonging to the relevant area, generating the corresponding Voronoi polygons, and, finally, labeling those polygons with their corresponding postal code.<\/p>\n\n\n\n<p>You can call the function by passing your area of interest (<em>e.g.<\/em>, one region of France) as a parameter called&nbsp;<code>p_geom<\/code>&nbsp;in the function.<\/p>\n\n\n\n<p>All the results are pushed into the table \u2018zips.voronoi\u2019.<\/p>\n\n\n\n<p>So now we have one polygon per geocoded address in the source. But postal codes are usually shared by multiple addresses. To get the complete boundaries for every postal code, you need to make the union between all the polygons with the same postal information. This can be done with the following PostgreSQL\/PostGIS query:&nbsp;<code>SELECT postcode, ST_union(geom) FROM zips.voronoi GROUP BY postcode<\/code><\/p>\n\n\n\n<p>The images below show the result of the Voronoi tessellation of the postal codes for a part of France.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" width=\"531\" height=\"450\" src=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/10\/Voronoi-tessellation-of-the-postal-codes-for-a-part-of-France.webp\" alt=\"\" class=\"wp-image-12538\" srcset=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/10\/Voronoi-tessellation-of-the-postal-codes-for-a-part-of-France.webp 531w, https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/10\/Voronoi-tessellation-of-the-postal-codes-for-a-part-of-France-300x254.webp 300w\" sizes=\"(max-width: 531px) 100vw, 531px\" \/><\/figure>\n\n\n\n<p><em>Points show the seeds colored by postal code, and lines show the resulting postal polygons after Voronoi generation and grouping by postal code.<\/em><\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"refining-postal-boundaries-using-administrative-divisions\">Refining Postcode Boundaries Using Administrative Divisions<\/h4>\n\n\n\n<p>The method above makes the most of the available data points, but you can improve the accuracy of your database if you know something about the postal system.<\/p>\n\n\n\n<p>Postcodes are most commonly based on administrative divisions. For instance, in France, postcodes usually cover one or more entire municipalities, locally known as communes. This knowledge can help you refine your postal boundaries by aligning them with municipalities.<\/p>\n\n\n\n<p>In theory, if your geocoded source is perfect\u2014in other words, it contains an exhaustive list of addresses with correct postcodes and coordinates\u2014you don\u2019t really need this extra step. But in practice, data sources are rarely perfect. Even if they were, this extra step means that if addresses are added in the future, you likely won\u2019t have to recompute the boundaries. Your postal boundaries will stay valid.<\/p>\n\n\n\n<p>So, how do you leverage administrative division data?<\/p>\n\n\n\n<p>French postcodes are based on municipalities, so you can construct French postal boundaries by aggregating municipalities. And, yes, you\u2019re right to think you could have skipped the Voronoi step altogether. But hang on. You\u2019ll see later that there are a few exceptions to the rule that one postal code covers one or more entire municipalities. This justifies using geocoded points in combination with the boundaries of municipalities.<\/p>\n\n\n\n<p>For this step, you\u2019ll use the&nbsp;<a href=\"https:\/\/www.data.gouv.fr\/en\/datasets\/decoupage-administratif-communal-francais-issu-d-openstreetmap\/\" target=\"_blank\" rel=\"noreferrer noopener\">latest version of the French communes, or municipalities, extracted from OpenStreetMap<\/a>. It\u2019s approved by the French Geographic Institute and mainly issued from the national cadastral division.<\/p>\n\n\n\n<p>Start by&nbsp;<a href=\"https:\/\/www.data.gouv.fr\/fr\/datasets\/decoupage-administratif-communal-francais-issu-d-openstreetmap\/\" target=\"_blank\" rel=\"noreferrer noopener\">downloading the municipalities<\/a>.<\/p>\n\n\n\n<p>Next, load the administrative boundaries table in&nbsp;<a href=\"https:\/\/www.qgis.org\/en\/site\/\" target=\"_blank\" rel=\"noreferrer noopener\">QGIS<\/a>&nbsp;by dragging the unzipped .shp file into a QGIS window. You will see a map of the French communes, and clicking on one commune will show you its properties, for instance, its name (\u201cnom\u201d in French), as shown below.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/Dcgg3BK.png\" alt=\"French communes boundaries\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/ZPI2mCi.png\" alt=\"Table of French communes\" \/><\/figure>\n\n\n\n<p>Next, unzip the file&nbsp;<code>adresses-france.csv.gz<\/code>&nbsp;(for example, with 7zip on Windows or the gzip utility in Unix systems) Then, upload the CSV with the geocoded addresses in QGIS so that you can look at both datasets simultaneously. In QGIS, you can import a CSV by clicking&nbsp;<strong>Layer<\/strong>,&nbsp;<strong>Add layer<\/strong>, and then&nbsp;<strong>Add delimited text layer<\/strong>. Select your address file and, if necessary, specify the latitude and longitude columns.<\/p>\n\n\n\n<p>It is helpful to color the address points by postal code. To do so, right-click on \u201caddress-france\u201d in the layers panel (by default on the left side in QGIS), then choose Properties, Symbology, on the top, Select Categorized instead of Single Symbol, then Select code_postal as Value, hit Classify at the bottom left and OK when it\u2019s done.<\/p>\n\n\n\n<p>You should obtain a map similar to the screenshot below, where the geocoded addresses are colored by postal code, and the black lines show the boundaries of the municipalities:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" width=\"531\" height=\"450\" src=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/10\/Voronoi-tessellation-of-the-postal-codes-for-a-part-of-France.webp\" alt=\"\" class=\"wp-image-12538\" srcset=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/10\/Voronoi-tessellation-of-the-postal-codes-for-a-part-of-France.webp 531w, https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/10\/Voronoi-tessellation-of-the-postal-codes-for-a-part-of-France-300x254.webp 300w\" sizes=\"(max-width: 531px) 100vw, 531px\" \/><\/figure>\n\n\n\n<p>This overlay clearly shows the pattern of municipalities covered by one postal code.&nbsp;Since you sometimes have to work with badly encoded data\u2014in other words, addresses with wrong coordinates or postcodes\u2014it\u2019s best to assign the most frequently occurring postal code from the geocoded addresses to a municipality.<\/p>\n\n\n\n<p>This is an example of leveraging your knowledge (each municipality has only one postal code) to remove some outliers in the data.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"dealing-with-exceptions\">Dealing with Exceptions<\/h4>\n\n\n\n<p>Of course, you always have to keep exceptions in mind.<\/p>\n\n\n\n<p>In this example, one municipality isn\u2019t&nbsp;<em>always<\/em>&nbsp;covered by a single postal code.&nbsp;Big municipalities like Paris, Lyon, or Marseille use several postcodes based on further administrative divisions, such as arrondissements in Paris.&nbsp;The map below shows geocoded addresses for Paris colored by postal code:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" width=\"681\" height=\"358\" src=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/10\/geocoded-addresses-for-Paris-colored-by-postal-code.webp\" alt=\"Geocoded addresses for Paris by postal code\" class=\"wp-image-12537\" srcset=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/10\/geocoded-addresses-for-Paris-colored-by-postal-code.webp 681w, https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/10\/geocoded-addresses-for-Paris-colored-by-postal-code-300x158.webp 300w\" sizes=\"(max-width: 681px) 100vw, 681px\" \/><\/figure>\n\n\n\n<p>It\u2019s also the case for a few smaller municipalities.<\/p>\n\n\n\n<p>To account for these exceptions, you need to allow some municipalities to be subdivided into several postal zones. For example, by applying the Voronoi algorithm to Paris&#8217;s data, you can obtain the postal boundaries below.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/wKR37aV.png\" alt=\"Voronoi algorithm of Paris postal boundaries\" \/><\/figure>\n\n\n\n<p>You can see that the result is much better than using only one postal code for the entire municipality of Paris. It is still not completely clean due to some badly encoded addresses in the initial dataset. You can refine these boundaries even more by finding polygons for the arrondissements of Paris.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"how-to-code-the-generation-of-postal-polygons\">How to Code the Generation of Postcode Polygons<\/h4>\n\n\n\n<p>Let\u2019s examine how all of this comes together with some code.<\/p>\n\n\n\n<p>In this example, you\u2019ll loop over all municipalities and look at the distribution of geocoded addresses they contain. You can set a percentage threshold as a parameter to see if one postal code is dominant. In that case, you will assign that postal code to the whole municipality and discard outliers.&nbsp;If not, you will subdivide the municipality into several postal zones corresponding to the different postcodes it contains.<\/p>\n\n\n\n<p>PL\/pgSQL lets you declare variables and records. It\u2019s best to define your parameters once as variables. Records variables are similar to row-type variables, but they have no predefined structure. They take on the actual row structure of the row they are assigned during a&nbsp;<code>FOR<\/code>&nbsp;command, looping over the rows returned by a&nbsp;<code>SELECT<\/code>.<\/p>\n\n\n\n<p>Here is the code for all these steps:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"postgresql\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">DO LANGUAGE plpgsql $$\nDECLARE\n\n\n   rec_reg record;\n   rec_pol record;\n\n\n   v_zip           varchar;\n   v_pc_points     numeric;\n   v_pc_zip_threshold numeric  := 90;\n\n\nBEGIN\n\n\n   ---------\n   --SETUP--\n   ---------\n\n\n   DROP TABLE IF EXISTS zips.zips_results;\n   CREATE TABLE zips.zips_results (\n       postcode varchar,\n       geom geometry\n   );\n   CREATE INDEX zips_results_sidx ON zips.zips_results USING gist (geom);\n   CREATE INDEX zips_results_zip ON zips.zips_results(zip);\n   ALTER TABLE zips.zips_results ADD CONSTRAINT zip_unique UNIQUE (postcode);\n\n\n   -- create table regrouped_voronoi\n   IF NOT EXISTS(SELECT * FROM information_schema.tables WHERE table_name='regrouped_voronoi' AND table_schema='zips')\n   THEN\n       CREATE TABLE zips.regrouped_voronoi (\n       postcode varchar (10),\n       geom geometry\n       );\n       CREATE INDEX regrouped_voronoi_zip_idx ON zips.regrouped_voronoi(ZIP);\n       CREATE INDEX regrouped_voronoi_sidx ON zips.regrouped_voronoi USING gist(geom);\n   END IF;\n\n\n-- LOOP OVER MUNICIPALITIES\n       FOR rec_reg IN\n           SELECT g.*\n           FROM zips.geom_source g\n\n\n       LOOP\n               -- split region geom into constitutive individual polygons\n               FOR rec_pol IN\n                   SELECT rec_reg.id,\n                   generate_series(1, ST_NumGeometries(rec_reg.geom)) num_polygon,\n                   ST_GeometryN(rec_reg.geom, generate_series(1, ST_NumGeometries(rec_reg.geom))) geom\n               LOOP\n\n                       -- reset variables\n                       v_zip := NULL;\n                       v_pc_points := 0;\n\n\n                       -------------------\n                       -- Assign top postcode class from points table if % points &gt; threshold\n                       WITH max_count AS (\n                           SELECT count(*) c\n                           FROM zips.source_points p\n                           WHER ST_Contains(rec_pol.geom, p.geom)\n                       )\n                       SELECT p.zip, 100 * count(*)\/ m.c INTO v_zip, v_pc_points\n                       FROM zips.source_points p , max_count m\n                       WHERE ST_Contains(rec_pol.geom, p.geom)\n                       GROUP BY p.zip, m.c\n                       ORDER BY 2 DESC\n                       LIMIT 1;   \n\n                       IF (v_zip IS NOT NULL AND v_pc_points &gt; v_pc_zip_threshold) THEN\n\n                           -- upsert into postcodes table: append geom or create new postcode row\n                           INSERT INTO zips.zips_results AS z (postcode, geom)\n                           VALUES (v_zip,  ST_Multi(rec_pol.geom))\n                           ON CONFLICT ON CONSTRAINT zip_unique\n                           DO UPDATE SET geom = ST_Makevalid(ST_Multi(ST_Union(rec_pol.geom, z.geom)))\n                               WHERE z.zip = v_zip;\n\n                       -- reset v_zip if threshold is not reached         \n                       ELSE \n                           -- generate Voronoi polygons with function\n                           PERFORM zips.voronoi_geom(rec_reg.geom, rec_reg.id);\n                           -- regroup in the table if polygons of the same postcode in work table\n                           TRUNCATE TABLE zips.regrouped_voronoi;\n\n                           INSERT INTO zips.regrouped_voronoi\n                           SELECT z.zip, ST_Union(z.geom) geom\n                           FROM zips.voronoi z\n                           WHERE z.zip = postcode\n                           GROUP BY z.zip;\n\n                           -- upsert destination table\n                           INSERT INTO zips.zips_results AS z\n                           SELECT t.zip, t.geom\n                           FROM zips.regrouped_voronoi t\n                           ON CONFLICT ON CONSTRAINT zip_unique\n                           DO UPDATE SET geom = ST_Makevalid(ST_Multi(ST_Union(excluded.geom, z.geom)))\n                               WHERE z.zip = excluded.zip;\n\n                       END IF;\n                   END LOOP;\n       END LOOP;\n\nEND;\n$$<\/pre>\n\n\n\n<p>The map below shows the results of the postal assignment before unifying the polygons corresponding to the same postal code:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2025\/02\/commune-png.webp\" alt=\"\" class=\"wp-image-4802\" \/><\/figure>\n\n\n\n<p>Now let\u2019s look at what it looks like after unifying them:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"869\" src=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/final-aggregate-1024x869.png\" alt=\"Postal assignment after unifying polygons\" class=\"wp-image-4802\" srcset=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/final-aggregate-1024x869.png 1024w, https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/final-aggregate-300x255.png 300w, https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/final-aggregate-768x652.png 768w, https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/final-aggregate.png 1266w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>The following two maps display the results of the different ways to produce postal boundaries. The first shows the outcome you got earlier when you obtained postal boundaries by using only the address data to generate Voronoi polygons:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"759\" src=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/Screenshot-from-2023-05-02-11-17-38-1024x759.png\" alt=\"Postal codes assigned using Voronoi point distribution\" class=\"wp-image-4806\" srcset=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/Screenshot-from-2023-05-02-11-17-38-1024x759.png 1024w, https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/Screenshot-from-2023-05-02-11-17-38-300x222.png 300w, https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/Screenshot-from-2023-05-02-11-17-38-768x569.png 768w, https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/Screenshot-from-2023-05-02-11-17-38.png 1086w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>The second one shows the outcome of the complete algorithm that leverages administrative divisions to constrain the postal assignment and only runs Voronoi if there are several postal codes within the same municipality:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"759\" src=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/Screenshot-from-2023-05-02-11-17-54-1024x759.png\" alt=\"Postal codes assigned according to administrative division\" class=\"wp-image-4807\" srcset=\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/Screenshot-from-2023-05-02-11-17-54-1024x759.png 1024w, https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/Screenshot-from-2023-05-02-11-17-54-300x222.png 300w, https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/Screenshot-from-2023-05-02-11-17-54-768x569.png 768w, https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/05\/Screenshot-from-2023-05-02-11-17-54.png 1086w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>The results are pretty close. The high quality of the simple Voronoi tessellation in this example can be attributed to the good quality of the address source\u2014many points are available and are properly geolocalized. The full algorithm filters out a few outliers, though. If the data from your address source were poorer, you can imagine that the improvement would have been even more pronounced.<\/p>\n\n\n\n<p>Congratulations! You have now built postcode polygons for France using two methods.<\/p>\n\n\n\n<p>You can apply these methods of creating a postcode database to other countries and with different administrative levels. This example is for a simple postcode system with high-quality data that\u2019s available in open source.<\/p>\n\n\n\n<p>Remember, though, that applying this method to several countries or aiming for high accuracy requires more work.<\/p>\n\n\n\n<p>Also, keep in mind that advanced data processing techniques, such as clustering or combining multiple data sources, will give you even more accurate results. It applies more generally, as well as if you want to deal with all special cases at once without needing to find detailed data for each of them. Advanced data processing techniques can help you correct or remove outliers. However, such techniques are beyond the scope of this article.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"toc-h2-3\">Conclusion<\/h2>\n\n\n\n<p>This article showed you how to define boundaries with postcodes using the example of France.<\/p>\n\n\n\n<p>As you can see, even with only one simple country, building postcode boundaries is not straightforward. You need a good source of geocoded data, gather information about the granularity of postcodes, find supporting administrative division boundaries, and deal with outliers and exceptions, including some this article didn\u2019t cover, such as polygons without any geocoded point.<\/p>\n\n\n\n<p>It\u2019s even more<a href=\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/the-7-challenges-of-building-a-standardized-zip-code-database\/\" target=\"_blank\" rel=\"noreferrer noopener\">&nbsp;<u>challenging<\/u><\/a>&nbsp;when you work on an international scale because each country\u2019s postcode system and available data are different. Processing data from multiple sources or working across several countries means you have to deal with misaligned data. You\u2019ll face overlaps or holes between neighboring polygons, especially at the borders of these sources.<\/p>\n\n\n\n<p>So, if you need accurate and clean<a href=\"https:\/\/www.geopostcodes.com\/en-GB\/postal-zip-code-database\/\" target=\"_blank\" rel=\"noreferrer noopener\">&nbsp;<u>postal data<\/u><\/a>&nbsp;at a large scale, you\u2019ll benefit from acquiring it from a specialized team. At GeoPostcodes, we maintain a worldwide database of postcode polygons based on hundreds of sources to spare you the hassle.<\/p>\n\n\n\n<p>We\u2019ve designed algorithms to deal with special cases such as outliers, enclaves, and stacked points to ensure perfectly aligned borders globally. We also offer<a href=\"https:\/\/www.geopostcodes.com\/en-GB\/boundaries-database\/\" target=\"_blank\" rel=\"noreferrer noopener\">&nbsp;<u>simplified boundaries<\/u><\/a>&nbsp;that are optimal for web visualization. And be warned: although simplification looks straightforward at first, it requires advanced techniques to prevent small polygons from disappearing and preserve perfectly aligned boundaries after simplification.<\/p>\n\n\n\n<p>You\u2019re welcome to&nbsp;<a href=\"https:\/\/www.geopostcodes.com\/en-GB\/\" target=\"_blank\" rel=\"noreferrer noopener\"><u>explore our data products<\/u><\/a> and feel free to&nbsp;<a href=\"https:\/\/linkedin.com\/in\/julien-lecach%C3%A9-9b734021b\" target=\"_blank\" rel=\"noreferrer noopener\"><u>reach out to me<\/u><\/a>&nbsp;if you want to discuss this topic further.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">FAQ<\/h2>\n\n\n\n<div id=\"wp-block-themeisle-blocks-accordion-aa5641a4\" class=\"wp-block-themeisle-blocks-accordion exclusive has-light-content-bg is-style-default\">\n<details class=\"wp-block-themeisle-blocks-accordion-item\"><summary class=\"wp-block-themeisle-blocks-accordion-item__title\"><div><strong>How can I integrate Google Maps API with a postal code polygon database?<\/strong><\/div><\/summary><div class=\"wp-block-themeisle-blocks-accordion-item__content\">\n<div style=\"height:40px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Integrating Google Maps API with a postal code polygon database allows for visualizing postal boundaries on a map.<\/p>\n\n\n\n<p>You can use the API to plot polygon data, enabling detailed geographic analysis and enhancing location-based services.<\/p>\n\n\n\n<div style=\"height:10px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n<\/div><\/details>\n\n\n\n<details class=\"wp-block-themeisle-blocks-accordion-item\"><summary class=\"wp-block-themeisle-blocks-accordion-item__title\"><div><strong>Does the United States Postal Service provide postal code polygon data?<\/strong><\/div><\/summary><div class=\"wp-block-themeisle-blocks-accordion-item__content\">\n<div style=\"height:40px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>The United States Postal Service (USPS) does not directly provide postal code polygon data.<\/p>\n\n\n\n<p>However, third-party providers aggregate this information from various sources.<\/p>\n\n\n\n<div style=\"height:10px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n<\/div><\/details>\n\n\n\n<details class=\"wp-block-themeisle-blocks-accordion-item\"><summary class=\"wp-block-themeisle-blocks-accordion-item__title\"><div><strong>How can I access postal code polygon data in SQL Server?<\/strong><\/div><\/summary><div class=\"wp-block-themeisle-blocks-accordion-item__content\">\n<div style=\"height:40px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>You can store and query postal code polygon data in SQL Server using spatial data types.<\/p>\n\n\n\n<p>By importing polygon shapefiles into SQL Server, you can perform geographic queries and integrate this data with other business intelligence tools.<\/p>\n\n\n\n<div style=\"height:10px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n<\/div><\/details>\n\n\n\n<details class=\"wp-block-themeisle-blocks-accordion-item\"><summary class=\"wp-block-themeisle-blocks-accordion-item__title\"><div><strong>What is the Zone Improvement Plan (POSTCODE) in relation to postal code polygons?<\/strong><\/div><\/summary><div class=\"wp-block-themeisle-blocks-accordion-item__content\">\n<div style=\"height:40px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>The Zone Improvement Plan (POSTCODE) was introduced by USPS to improve mail delivery efficiency.<\/p>\n\n\n\n<p>Postal code polygons represent the geographic areas served by each Postcode, which helps in optimizing logistics and delivery routes.<\/p>\n\n\n\n<div style=\"height:10px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n<\/div><\/details>\n\n\n\n<details class=\"wp-block-themeisle-blocks-accordion-item\"><summary class=\"wp-block-themeisle-blocks-accordion-item__title\"><div><strong>Why do some Postcode regions have strange assignments?<\/strong><\/div><\/summary><div class=\"wp-block-themeisle-blocks-accordion-item__content\">\n<div style=\"height:40px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>The United States Postal Service (USPS) creates Postcode regions based on mail delivery routes, not geographic boundaries.<\/p>\n\n\n\n<p>This can result in strange Postcode assignments, especially in mid-sized urban areas or locations with a sparse network of addresses.<\/p>\n\n\n\n<div style=\"height:10px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n<\/div><\/details>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to create a database that maps postal code boundaries for accurate geographic analysis and visualization.<\/p>\n","protected":false},"author":16,"featured_media":11318,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"set","_themeisle_gutenberg_block_has_review":false,"footnotes":""},"categories":[57],"tags":[37],"class_list":["post-27726","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-map-visualization","tag-boundaries-product-page"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.7 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Tutorial: Build a Zip Code Polygon Database<\/title>\n<meta name=\"description\" content=\"Learn how to create a database that maps postal code boundaries for accurate geographic analysis and visualization.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Tutorial: Build a Zip Code Polygon Database\" \/>\n<meta property=\"og:description\" content=\"Learn how to create a database that maps postal code boundaries for accurate geographic analysis and visualization.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/\" \/>\n<meta property=\"og:site_name\" content=\"GeoPostcodes\" \/>\n<meta property=\"article:published_time\" content=\"2025-02-23T18:04:08+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-04-01T07:01:01+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.geopostcodes.com\/wp-content\/uploads\/2023\/04\/Building-a-zipcode-polygon-database.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"828\" \/>\n\t<meta property=\"og:image:height\" content=\"346\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"author\" content=\"Julien Lecach\u00e9\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Julien Lecach\u00e9\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"17 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/\"},\"author\":{\"name\":\"Julien Lecach\u00e9\",\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/#\/schema\/person\/5a8c8e9dc194c184a4ead6a8d3f2d0c7\"},\"headline\":\"How to Build a Postcode Polygon Database\",\"datePublished\":\"2025-02-23T18:04:08+00:00\",\"dateModified\":\"2026-04-01T07:01:01+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/\"},\"wordCount\":3282,\"publisher\":{\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/04\/Building-a-zipcode-polygon-database.webp\",\"keywords\":[\"Boundaries product page\"],\"articleSection\":[\"Map Visualization\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/\",\"url\":\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/\",\"name\":\"Tutorial: Build a Zip Code Polygon Database\",\"isPartOf\":{\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/04\/Building-a-zipcode-polygon-database.webp\",\"datePublished\":\"2025-02-23T18:04:08+00:00\",\"dateModified\":\"2026-04-01T07:01:01+00:00\",\"description\":\"Learn how to create a database that maps postal code boundaries for accurate geographic analysis and visualization.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/#primaryimage\",\"url\":\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/04\/Building-a-zipcode-polygon-database.webp\",\"contentUrl\":\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/04\/Building-a-zipcode-polygon-database.webp\",\"width\":828,\"height\":346,\"caption\":\"GeoPostcodes-Building-a-zipcode-polygon-database\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.geopostcodes.be\/en-GB\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Build a Zip Code Polygon Database\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/#website\",\"url\":\"https:\/\/www.geopostcodes.com\/en-GB\/\",\"name\":\"GeoPostcodes\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.geopostcodes.com\/en-GB\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/#organization\",\"name\":\"GeoPostcodes\",\"url\":\"https:\/\/www.geopostcodes.com\/en-GB\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2021\/04\/cropped-GeoPostcodes-color@2x-png.webp\",\"contentUrl\":\"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2021\/04\/cropped-GeoPostcodes-color@2x-png.webp\",\"width\":1331,\"height\":207,\"caption\":\"GeoPostcodes\"},\"image\":{\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/#\/schema\/person\/5a8c8e9dc194c184a4ead6a8d3f2d0c7\",\"name\":\"Julien Lecach\u00e9\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.geopostcodes.com\/en-GB\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/www.geopostcodes.com\/wp-content\/uploads\/2025\/03\/cropped-Julien-L-scaled-1-512x512.webp\",\"contentUrl\":\"https:\/\/www.geopostcodes.com\/wp-content\/uploads\/2025\/03\/cropped-Julien-L-scaled-1-512x512.webp\",\"caption\":\"Julien Lecach\u00e9\"},\"description\":\"My name is Julien Lecach\u00e9. I'm a Geomatician specializing in the Boundary product at Geopostcodes. My team and I maintain the postal database up to date. I\u2019m currently developing tools using PostGIS in PostgreSQL and PL\/pgSQL (also Mapshaper, GDAL, and bash\u2026) I hold a Master\u2019s in Geomatics applied to urban studies and risks, from the University of Cergy Paris, France. My previous experience revolves around topics related to GIS apps in the field, transforming topographic maps to GIS, dashboards for decision-making, etc. I am interested in everything related to Geographic information systems, open source, open data, databases (PostgreSQL), programming languages\/managing data (Python, SQL, R), and Linux. I'm an OpenStreetMap enthusiastic and I enjoy contributing to mapping the most vulnerable places for humanitarian causes. Like a good Geographer, I enjoy discovering the world both through maps and with my backpack.\",\"url\":\"https:\/\/www.geopostcodes.com\/en-GB\/blog\/author\/julien-l\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Tutorial: Build a Zip Code Polygon Database","description":"Learn how to create a database that maps postal code boundaries for accurate geographic analysis and visualization.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/","og_locale":"en_US","og_type":"article","og_title":"Tutorial: Build a Zip Code Polygon Database","og_description":"Learn how to create a database that maps postal code boundaries for accurate geographic analysis and visualization.","og_url":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/","og_site_name":"GeoPostcodes","article_published_time":"2025-02-23T18:04:08+00:00","article_modified_time":"2026-04-01T07:01:01+00:00","og_image":[{"width":828,"height":346,"url":"https:\/\/www.geopostcodes.com\/wp-content\/uploads\/2023\/04\/Building-a-zipcode-polygon-database.webp","type":"image\/webp"}],"author":"Julien Lecach\u00e9","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Julien Lecach\u00e9","Est. reading time":"17 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/#article","isPartOf":{"@id":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/"},"author":{"name":"Julien Lecach\u00e9","@id":"https:\/\/www.geopostcodes.com\/en-GB\/#\/schema\/person\/5a8c8e9dc194c184a4ead6a8d3f2d0c7"},"headline":"How to Build a Postcode Polygon Database","datePublished":"2025-02-23T18:04:08+00:00","dateModified":"2026-04-01T07:01:01+00:00","mainEntityOfPage":{"@id":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/"},"wordCount":3282,"publisher":{"@id":"https:\/\/www.geopostcodes.com\/en-GB\/#organization"},"image":{"@id":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/#primaryimage"},"thumbnailUrl":"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/04\/Building-a-zipcode-polygon-database.webp","keywords":["Boundaries product page"],"articleSection":["Map Visualization"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/","url":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/","name":"Tutorial: Build a Zip Code Polygon Database","isPartOf":{"@id":"https:\/\/www.geopostcodes.com\/en-GB\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/#primaryimage"},"image":{"@id":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/#primaryimage"},"thumbnailUrl":"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/04\/Building-a-zipcode-polygon-database.webp","datePublished":"2025-02-23T18:04:08+00:00","dateModified":"2026-04-01T07:01:01+00:00","description":"Learn how to create a database that maps postal code boundaries for accurate geographic analysis and visualization.","breadcrumb":{"@id":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/#primaryimage","url":"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/04\/Building-a-zipcode-polygon-database.webp","contentUrl":"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/04\/Building-a-zipcode-polygon-database.webp","width":828,"height":346,"caption":"GeoPostcodes-Building-a-zipcode-polygon-database"},{"@type":"BreadcrumbList","@id":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/postal-code-polygon-database\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.geopostcodes.be\/en-GB\/"},{"@type":"ListItem","position":2,"name":"How to Build a Zip Code Polygon Database"}]},{"@type":"WebSite","@id":"https:\/\/www.geopostcodes.com\/en-GB\/#website","url":"https:\/\/www.geopostcodes.com\/en-GB\/","name":"GeoPostcodes","description":"","publisher":{"@id":"https:\/\/www.geopostcodes.com\/en-GB\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.geopostcodes.com\/en-GB\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.geopostcodes.com\/en-GB\/#organization","name":"GeoPostcodes","url":"https:\/\/www.geopostcodes.com\/en-GB\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.geopostcodes.com\/en-GB\/#\/schema\/logo\/image\/","url":"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2021\/04\/cropped-GeoPostcodes-color@2x-png.webp","contentUrl":"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2021\/04\/cropped-GeoPostcodes-color@2x-png.webp","width":1331,"height":207,"caption":"GeoPostcodes"},"image":{"@id":"https:\/\/www.geopostcodes.com\/en-GB\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.geopostcodes.com\/en-GB\/#\/schema\/person\/5a8c8e9dc194c184a4ead6a8d3f2d0c7","name":"Julien Lecach\u00e9","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.geopostcodes.com\/en-GB\/#\/schema\/person\/image\/","url":"https:\/\/www.geopostcodes.com\/wp-content\/uploads\/2025\/03\/cropped-Julien-L-scaled-1-512x512.webp","contentUrl":"https:\/\/www.geopostcodes.com\/wp-content\/uploads\/2025\/03\/cropped-Julien-L-scaled-1-512x512.webp","caption":"Julien Lecach\u00e9"},"description":"My name is Julien Lecach\u00e9. I'm a Geomatician specializing in the Boundary product at Geopostcodes. My team and I maintain the postal database up to date. I\u2019m currently developing tools using PostGIS in PostgreSQL and PL\/pgSQL (also Mapshaper, GDAL, and bash\u2026) I hold a Master\u2019s in Geomatics applied to urban studies and risks, from the University of Cergy Paris, France. My previous experience revolves around topics related to GIS apps in the field, transforming topographic maps to GIS, dashboards for decision-making, etc. I am interested in everything related to Geographic information systems, open source, open data, databases (PostgreSQL), programming languages\/managing data (Python, SQL, R), and Linux. I'm an OpenStreetMap enthusiastic and I enjoy contributing to mapping the most vulnerable places for humanitarian causes. Like a good Geographer, I enjoy discovering the world both through maps and with my backpack.","url":"https:\/\/www.geopostcodes.com\/en-GB\/blog\/author\/julien-l\/"}]}},"jetpack_featured_media_url":"https:\/\/www.geopostcodes.com\/en-GB\/wp-content\/uploads\/2023\/04\/Building-a-zipcode-polygon-database.webp","_links":{"self":[{"href":"https:\/\/www.geopostcodes.com\/en-GB\/wp-json\/wp\/v2\/posts\/27726","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.geopostcodes.com\/en-GB\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.geopostcodes.com\/en-GB\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.geopostcodes.com\/en-GB\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/www.geopostcodes.com\/en-GB\/wp-json\/wp\/v2\/comments?post=27726"}],"version-history":[{"count":0,"href":"https:\/\/www.geopostcodes.com\/en-GB\/wp-json\/wp\/v2\/posts\/27726\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.geopostcodes.com\/en-GB\/wp-json\/wp\/v2\/media\/11318"}],"wp:attachment":[{"href":"https:\/\/www.geopostcodes.com\/en-GB\/wp-json\/wp\/v2\/media?parent=27726"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.geopostcodes.com\/en-GB\/wp-json\/wp\/v2\/categories?post=27726"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.geopostcodes.com\/en-GB\/wp-json\/wp\/v2\/tags?post=27726"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}