Working With NYC Election Maps Is An Exercise In Pain
I spent three days in 2018 trying to pull precinct boundary data for a municipal election project. What I thought would take an afternoon turned into a wrestling match with shapefiles, inconsistent coordinate systems, and a city that redraws districts every census cycle without giving anyone much advance warning. The New York City Board of Elections maintains precinct maps, but they are not exactly developer-friendly. You will deal with shapefiles from multiple boroughs, some precincts split across counties, and a naming convention that makes programmatic merging a nightmare. Here is what I actually did, step by step, after the fourth failed attempt. The core problem is that NYC precinct data lives in a few different places depending on which borough you care about. Manhattan and the Bronx share a dataset. Brooklyn, Queens, and Staten Island each have their own flavors. The NYC Department of City Planning publishes precinct maps through the PLUTO dataset, but that tracks tax lots, not election precincts. For actual voting boundaries, you need the Board of Elections resources or the NYC Open Data portal. I started by downloading the most recent precinct shapefile from the NYC Open Data catalog under "Precincts" — the one maintained by the NYC Board of Elections. It comes as a zipped folder containing a .shp file, a .dbf attribute table, and a handful of companion files. The trick is figuring out which projection it uses. Most of these files come in NAD 1983 StatePlane New York Long Island FIPS 3104 feet, which is fine until you try to overlay them on anything else.
Reprojection happens inside your GIS tool of choice. QGIS handles it without trouble: open the shapefile, right-click the layer, go to Layer Properties, then CRS. Reproject to EPSG:4326 if you want latitude and longitude, or stick with the StatePlane system if you are working locally. Do this before joining any other data, because spatial joins will be inaccurate otherwise. This usually takes about five minutes per borough. The attribute table contains fields like PRECINCT, COUNTY, and BORO, along with population estimates and registered voter counts. One thing that caught me off guard: the precinct numbering is not unique across the entire city. Manhattan uses a simple numeric system. Brooklyn sometimes uses alphanumeric codes. Queens mixes both. If you are building a unified map, you need a composite key made from BORO and PRECINCT combined, otherwise you will end up with duplicate IDs and broken joins. Here is the edge case that nearly ruined my project. I found precinct 14A in Kings County, which is Brooklyn, but there was also a precinct labeled just 14 in the same county from an older dataset I had pulled for comparison. They looked identical in the attribute table, but the geometries were completely different. The older file was from the 2012 redistricting cycle. The new one was post-2020. If you blend them without checking the year or the official version number in the metadata, you will be mapping voters to the wrong polling places. I wrote a quick script using Python and geopandas to cross-reference the polygon centroids against the latest Board of Elections polling location list, and removed any records where the distance exceeded fifty meters. That filtered out about eight percent of the problematic overlap.
For visualization purposes, I used Mapbox GL or Leaflet with GeoJSON. Converting the shapefile to GeoJSON is straightforward withogr2ogr, a command-line tool that ships with GDAL. Run a command like ogr2ogr -f GeoJSON precincts.json precincts.shp -t_srs EPSG:4326 and you will have a file ready to drop into any web map. I usually add a filter in the JavaScript to only show precincts for a given borough when the user selects one from a dropdown, because loading all twelve hundred precincts at once makes the browser chug. One counter-intuitive thing nobody warns you about: precinct boundaries shift slightly every election cycle, but not every change is reflected in the published shapefile. The Board of Elections occasionally adjusts precinct lines mid-cycle due to polling place closures or demographic shifts. These changes appear in their annual reports but not necessarily in the downloadable dataset. If you need the absolute latest boundaries for an upcoming election, check their press releases or email the data coordinator directly. I learned this the hard way when a precinct I was analyzing vanished from the map between the January release and the March election because a school was rezoned for construction. If you need higher precision than the standard shapefile gives you, there is an alternative path through the NYC Planning Labs dataset, which includes census block and tabulation area geometry at a finer resolution. It requires more computational overhead but produces cleaner boundaries for small areas. I typically use the Board of Elections shapefile for quick work and the census-derived data when I need something publication-quality.
Get the Full Details

Download links are always moving, so I do not paste direct URLs. Go to nyc.gov/data, search for "election precincts," and pick the version dated closest to your target election year. If you run into issues with file encoding in the .dbf table, open it in a text editor and check for UTF-8 issues. Some of the older precinct labels contain special characters that break parsers unless you tell the reader explicitly to expect Latin-1 encoding. The whole process, once you have the tools installed, takes roughly twenty minutes for a single borough and about an hour if you are processing all five. The bottleneck is always the reprojection and the deduplication logic. Automate that part and you save most of the friction.