<!DOCTYPE html> <html lang="en"> <head> <script defer="" data-domain="nycbookstores.org" src="https://stats.yetaga.in/js/script.outbound-links.js" ></script> <meta charset="utf-8" /> <meta http-equiv="x-ua-compatible" content="ie=edge" /> <title> Independent Bookstores in New York City - Best Community Bookstores in NYC </title> <meta name="google-site-verification" content="hEfog9h0E3JQW91ZUZM5ayPb6DND0WbUa2_W8yTIuVw" /> <link rel="icon" type="image/png" href="/img/favicon.png" /> <link rel="apple-touch-icon" href="/img/social.jpg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script src="https://api.mapbox.com/mapbox-gl-js/v2.13.0/mapbox-gl.js"></script> <link href="https://api.mapbox.com/mapbox-gl-js/v2.13.0/mapbox-gl.css" rel="stylesheet" /> <link href="https://fonts.googleapis.com/css?family=Acme|Lato&display=swap" rel="stylesheet" /> <link media="screen" rel="stylesheet" type="text/css" href="/site.css?1734659401621" /> <meta property="title" name="title" content="Independent Bookstores in New York City - Best Community Bookstores in NYC" /> <meta property="description" name="description" content="A guide to and map of every independent bookstore in New York City. We have a complete list of community bookstores in NYC with locations and descriptions." /> <meta name="twitter:card" content="summary" /> <meta name="twitter:site" content="www.nycbookstores.org" /> <meta name="twitter:title" content="NYC Bookstores" /> <meta name="twitter:description" content="A Guide To The Many Independent Bookstores Of New York City" /> <meta name="twitter:image" content="https://www.nycbookstores.org/img/social.jpg" /> <meta property="og:url" content="https://www.nycbookstores.org/" /> <meta property="og:type" content="website" /> <meta property="og:title" content="NYC Bookstores" /> <meta property="og:description" content="A Guide To The Many Independent Bookstores Of New York City" /> <meta property="og:image" content="https://www.nycbookstores.org/img/social.jpg" /> <link rel="canonical" href="https://www.nycbookstores.org/" /> </head> <body> <div id="wrapper"> <h1>NYC Bookstores</h1> <div> <ul class="nav"> <li> <h2 id="subhed"> The Many Independent Bookstores of New York City </h2> </li> <li> <a id="viewInfo" href="/">intro</a> </li> <li> <a href="https://git.yetaga.in/alazyreader/nyc-bookstores/" target="_blank" >source</a > </li> <li> <a href="https://icosahedron.website/@lazyreader" target="_blank" >@lazyreader</a > </li> </ul> </div> <div class="container"> <div id="map"></div> <div id="info"> <p> New York City loves its independent bookstores. It <a href="https://www.nytimes.com/2006/10/15/nyregion/thecity/15book.html" target="_blank" >eulogizes those that have faded</a > and celebrates when new ventures are launched. And while the historic <a href="https://untappedcities.com/2015/08/26/4th-avenue-the-history-of-nycs-book-row/" target="_blank" >Book Row may have passed away in the 80s</a >, there are still many indie bookstores dotting the map, across all five boroughs. Here, I have attempted to collect all of the currently-open general-interest independent booksellers in NYC. Any store with regular-ish hours (excluding religious booksellers and appointment-only rare book sellers) is included. </p> <p> While Manhattan and Brooklyn still lead the pack, Queens has a respectable number of stores, and all five boroughs are represented, with the Bronx and Staten Island both hosting lone independent stores. Lower Manhattan has the highest density of booksellers. </p> <p> The listings here are kept up-to-date to the best of my ability; however, I make no promises about either the accuracy or reliability of the information. If you spot an error, or I've missed a shop, please let me know by <a href="mailto:delta.mu.alpha@gmail.com" target="_blank">email</a>, <a href="https://icosahedron.website/@lazyreader" target="_blank" >mastodon</a >, or <a href="https://www.twitter.com/alazyreader" target="_blank" >twitter</a >. Originally based on the "<a href="https://github.com/jlord/hack-spots" target="_blank" >Hack Spots</a >" website by <a href="https://www.twitter.com/jllord" target="_blank">@jllord</a> (although I don't believe any of the actual underlying code still survives at this point). </p> <p> There are currently <span id="storeCount">121</span> stores indexed on this page. Last updated <span id="updatedOn">December 19, 2024</span>. </p> <details> <summary>Recent Changes</summary> <ul id="changesList"></ul> </details> </div> <div id="selected"></div> </div> <div class="clearfix"></div> <div class="container"> <div id="Stores"> <table> <tbody></tbody> </table> </div> </div> </div> <!-- end wrapper --> <script> mapboxgl.accessToken = "pk.eyJ1IjoiYWxhenlyZWFkZXIiLCJhIjoiY2lucDZhb2JxMHp6MHRxa2pvaTFoOWpuZyJ9.DILGYYxxt7A-A_lHHwp6tQ"; var map = new mapboxgl.Map({ container: "map", style: "mapbox://styles/mapbox/basic-v9", center: [-73.957292, 40.729071], // arbitrary center point zoom: 9, minZoom: 9, maxZoom: 17, dragRotate: false, }); var popup = new mapboxgl.Popup({ closeOnClick: false, closeButton: false, }); function TitleTemplate({ name }) { return `${name} | Independent Bookstores in New York City - Best Community Bookstores in NYC`; } function TableViewTemplate(rows) { table = "<table>"; rows.forEach((row) => { table = table + TableRowTemplate(row); }); return table + "</table>"; } function TableRowTemplate({ rowNumber, name, address, city }) { return `<tr id="${rowNumber}" class="spotRow"> <td class="name">${name}</td><td>${address}, ${city}</td> </tr>`; } function SelectedStoreTemplate({ name, address, city, postcode, website, events, cafe, description, }) { const isAppleIsh = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform); return ` <h2>${name}</h2> <p class="address">${address}</p> <p></p> <p class="address"> ${city}, NY ${postcode} </p> <p> View in: <a href="https://maps.google.com/maps?q=${encodeURIComponent( name )}+${address},${city},NY" target="_blank" >Google Maps</a > ${ isAppleIsh ? ` <a href="http://maps.apple.com/?q=${encodeURIComponent( name )}&address=${address},${city},NY" target="_blank" >Apple Maps</a >` : "" } </p> <ul> ${ website ? `<li><a href="${website}" target="_blank">${cleanWebsite( website )}</a></li>` : "" } <li class="storeDetails">Events: ${events}</li> <li class="storeDetails">Café: ${cafe}</li> </ul> ${description ? `<p class="description">${description}</p>` : ""}`; } function hideElementById(id) { const element = document.getElementById(id); if (element !== undefined) { element.classList.add("hidden"); } } function showElementById(id) { const element = document.getElementById(id); if (element !== undefined) { element.classList.remove("hidden"); } } function setContent(id, html) { const element = document.getElementById(id); if (element !== undefined) { element.innerHTML = html; } } function setTitle(string) { const element = document.getElementsByTagName("title"); if (element !== undefined && element.length === 1) { element[0].innerText = string; } } document.addEventListener("DOMContentLoaded", function () { if (window.location.hash !== "") { updateLocation(window.location.hash.substring(1)); } fetch("/stores.json") .then((resp) => { return resp.json(); }) .then((data) => { data.sort(function (a, b) { var aname = a.name.toLowerCase(); var bname = b.name.toLowerCase(); return aname === bname ? 0 : +(aname > bname) || -1; }); data.forEach((value, key) => { value.rowNumber = key; value.slug = slugify(value.name); }); setContent("storeCount", data.length); window.data = data; loadMap(data); }) .catch((err) => { // we'll live with the static cache! console.log(err); }); }); function updateLocation(slug) { history.pushState(null, null, `/${slug}`); } function slugify(str) { return str .toLowerCase() .replace(/é/g, "e") .replace(/&/g, " and ") .replace(/ /g, "-") .replace(/[']+/g, "") .replace(/[^\w-]+/g, "-") .replace(/-+/g, "-") .replace(/^-|-$/g, ""); } function cleanWebsite(str) { return str .toLowerCase() .replace(/^https?:\/\//g, "") .replace(/^www./g, "") .replace(/\/$/g, ""); } function getStoreBySlug(slug) { var ret = false; window.data.forEach((value, key) => { if (value.slug === slug) { ret = value; return false; } }); return ret; } function updateViewBySlug(slug) { if (slug === undefined) { showInfo(false); } else { var store = getStoreBySlug(slug); if (store) { updateSelectedStore(store, false); } } } function boundingBox(point) { // add some buffer to a point to give the user some leeway return [ [point.x - 5, point.y - 5], [point.x + 5, point.y + 5], ]; } function updateSelectedStore(store, pushState = false) { map.flyTo({ center: [store.long, store.lat], zoom: 12 }); popup.setLngLat([store.long, store.lat]).setHTML(store.name).addTo(map); hideElementById("info"); setContent("selected", SelectedStoreTemplate(store)); showElementById("selected"); setTitle(TitleTemplate(store)); if (pushState) { updateLocation(store.slug); } } function showInfo(pushState = true) { hideElementById("selected"); popup.remove(); showElementById("info"); if (pushState) { updateLocation("info"); } } function loadMap(data) { var geolocate = new mapboxgl.GeolocateControl(); var points = []; data.forEach((value, key) => { points.push({ type: "Feature", geometry: { type: "Point", coordinates: [value.long, value.lat], }, properties: value, }); }); map.on("load", function () { map.addLayer({ id: "stores", type: "circle", source: { type: "geojson", data: { type: "FeatureCollection", features: points, }, }, paint: { "circle-radius": 5, "circle-color": "#B9FCFC", "circle-stroke-width": 2, "circle-stroke-color": "#000000", }, }); map.addControl(new mapboxgl.NavigationControl(), "top-left"); map.addControl(geolocate, "top-right"); updateViewBySlug(window.location.pathname.split("/")[1]); }); map.on("click", function (e) { if (!map.getLayer("stores")) { return; } popup.remove(); // Use queryRenderedFeatures to get features at a click event's point var features = map.queryRenderedFeatures(boundingBox(e.point), { layers: ["stores"], }); // fly to the location of the click event if (features.length) { var store = features[0]; // Get coordinates from the symbol and center the map on those coordinates updateSelectedStore(store.properties, true); } }); // indicate that the symbols are clickable by changing the cursor style to 'pointer'. map.on("mousemove", function (e) { if (!map.getLayer("stores")) { return; } var features = map.queryRenderedFeatures(boundingBox(e.point), { layers: ["stores"], }); map.getCanvas().style.cursor = features.length ? "pointer" : ""; }); geolocate.on("geolocate", function (e) { map.setZoom(14); popup .setLngLat([e.coords.longitude, e.coords.latitude]) .setHTML("Current Location") .addTo(map); }); } </script> </body> </html>