GeoBeerMap

A static directory and interactive Leaflet map cataloguing craft beer venues across Georgia, built for travellers and locals navigating a wine-centric country. Every venue is a plain-text file with coordinates and contact details, pre-rendered into fast pages and filterable markers.

GeoBeerMap home screen showing a dark Mapbox map of Tbilisi dotted with yellow beer location pins beside a left sidebar listing breweries and bars like 2 Tons Mukhiani, 9 Mta and Amphora Beer with Facebook, Instagram and website icons above a search field
Client

GeoBeerMap

Status

Live

Introduction

A directory and interactive map of Georgia's craft beer scene — breweries, bars, and retailers across Tbilisi, Batumi, and beyond — built for travellers and locals trying to find good beer in a country better known for wine. Each venue lives as a plain text file with its coordinates and contact details, which the site turns into map markers, a filterable sidebar, and a dedicated page for every location, all pre-rendered as static HTML so it loads fast anywhere.

GeoBeerMap Contact page on a dark navy background, with a yellow beer-glass logo, Home and Contact navigation links, and a "Contact Us" form containing Name, Email, and Message fields above a teal Submit button and a GitHub Repository link

The Challenge

Georgia is better known for its wine culture than craft beer, leaving visitors and locals with no central resource to discover breweries, bars, and beer retailers across Tbilisi, Batumi, and beyond. The challenge was to aggregate scattered venue information into a single searchable directory and map that would load quickly anywhere, stay easy to update, and remain viable as a solo-maintained side project without a backend or database infrastructure.

The Outcome

Launched a searchable directory and interactive map of craft beer venues across Georgia.

Tech Stack

Frontend

  • React
  • Mapbox
  • Gatsby
  • Leaflet
  • React-Leaflet
  • CSS Modules
  • React Helmet

Language

  • GraphQL
  • JavaScript
  • MDX

Backend

  • Sharp

CMS

  • Netlify CMS

DevOps

  • Netlify
  • GitHub

Tooling

  • Remark
  • Google Analytics
  • Gatsby 2 + React 17 static site generator, chosen so a data-heavy directory can be compiled to static pages at build time rather than queried at runtime
  • GraphQL as the internal data layer — venue and blog content is sourced from the filesystem and queried in gatsby-node.js to generate pages
  • MDX content files (entries/ for venues, blog/ for posts) processed through Remark plugins for responsive images and iframes
  • Leaflet + React-Leaflet for the interactive map, with Mapbox tiles
  • Netlify CMS (netlify-cms-app) with GitHub authentication, giving a browser-based editing UI that commits straight back to the repo
  • CSS Modules for component-scoped styling, one stylesheet per component directory
  • React Helmet for per-page SEO metadata, plus Gatsby's sitemap and robots.txt plugins
  • Sharp image processing via gatsby-plugin-sharp / gatsby-image for venue logos and photos
  • Google Analytics through gatsby-plugin-google-gtag, configured with anonymize_ip and respectDNT
  • Deployed on Netlify, with build behaviour driven by Netlify's deploy-context environment variables

Key Implementation Details

Files-as-database content model

  • Every venue is an MDX file with structured frontmatter: coordinates, address, city, country, opening status, beer list, and links to website, Facebook, Instagram, Untappd, and Google Maps
  • A custom createSchemaCustomization step declares the full MdxFrontmatter type explicitly, so optional fields (e.g. a venue with no Instagram) don't break the GraphQL schema or the build
  • Editors never touch the code — Netlify CMS writes new entries as commits, which triggers a fresh Netlify build

Programmatic page generation from two content sources

  • A single GraphQL query in gatsby-node.js splits content by file path regex — /blog/ for posts, /entries/ for venues — and pipes each set into its own React template
  • Venue entries are filtered on the open field so incomplete or unpublished records are excluded from the build
  • Blog posts are sorted by frontmatter date, and pages are created with only an id in context, letting each template fetch exactly the fields it needs

Map, sidebar, and search as one connected view

  • MapContainer coordinates a Leaflet map, custom MapMarker popups, a MapSidebar list, and a SearchBox, so filtering by category (brewery, bar, retailer) updates both the list and the markers
  • Coordinates parsed out of frontmatter are reused on individual entry pages to render a location-specific map
  • gatsby-plugin-react-leaflet handles the CDN stylesheet loading that Leaflet normally requires manual setup for

Deploy-context-aware crawling and SEO

  • gatsby-config.js reads Netlify's CONTEXT, URL, and DEPLOY_PRIME_URL variables to compute the canonical site URL per environment
  • gatsby-plugin-robots-txt emits a permissive policy in production but a full disallow with no sitemap on branch deploys and deploy previews, preventing staging URLs from being indexed
  • A shared SEO.js component with React Helmet centralises titles (via a titleTemplate), descriptions, and social images from siteMetadata

Responsive navigation built from scratch

  • The hamburger menu is split into container, button, and panel components, each with its own CSS Module
  • A custom MenuCloseHook handles outside-click/route-change dismissal, keeping the state logic reusable and out of the markup

What I Contributed

  • Architected a files-as-database content model where each venue is an MDX file with structured frontmatter (coordinates, contact details, social links), enabling non-technical updates through Netlify CMS that trigger automatic rebuilds without touching code.
  • Built a unified map and directory view coupling Leaflet markers, a filterable sidebar, and a search box so category selections (brewery, bar, retailer) update both the list and the map in sync.
  • Implemented programmatic page generation in gatsby-node.js by querying all MDX files, splitting them by path regex into venues and blog posts, and piping each set into dedicated React templates with a custom GraphQL schema to handle optional frontmatter fields.
  • Configured deploy-context-aware SEO and robots.txt policies that read Netlify environment variables to allow crawling in production while blocking branch deploys and previews from being indexed.

Outcome

  • Earned strong organic search visibility for craft beer searches relating to Georgia.

  • Received direct feedback from multiple users and brewery owners describing the platform as useful and requesting updates to venue information.

The directory has earned strong organic search visibility for craft beer searches relating to Georgia. Multiple users and brewery owners have contacted me to request updates to venue information and say how useful they find the platform. It remains live, with a backlog of venue-information updates to work through.