diff --git a/database.py b/database.py
index 44e9e7aa64e4a5bd0a0f6c0964372d8af6a7bcb9..a120ee9caf62a0db9788fdbfee092bf2d8742d0e 100644
--- a/database.py
+++ b/database.py
@@ -1,6 +1,6 @@
 import os
 import sqlite3
-from typing import List
+from typing import List, Tuple
 
 DATABASE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "database.db")
 
@@ -50,8 +50,25 @@ with Connection() as conn:
 		url text NOT NULL,
 		workspace_id integer NOT NULL,
 		FOREIGN KEY (workspace_id) REFERENCES Workspaces(id))''')
+	conn.execute('''CREATE TABLE IF NOT EXISTS AddressToLatLong (
+		id integer NOT NULL PRIMARY KEY AUTOINCREMENT,
+		address text NOT NULL,
+		latlong text NOT NULL)''')
 	conn.commit()
 
+def lookup_address(address: str):
+	with Connection() as conn:
+		conn.execute("SELECT latlong FROM AddressToLatLong WHERE address = ?", (address,))
+		res = conn.cursor.fetchone()[0]
+		(lat, long) = res.split(",")
+		return (float(lat), float(long))
+
+def set_address_latlong(address: str, latlong: Tuple[float, float]):
+	with Connection() as conn:
+		latlong_str = f"{ repr(latlong[0]) },{ repr(latlong[1]) }"
+		conn.execute("INSERT INTO AddressToLatLong (address, latlong) VALUES (?, ?)", (address, latlong_str))
+		conn.commit()
+
 class Workspace:
 	def __init__(self, name: str,
 		address: str, main_photo: str, additional_photos: List[str], description: str,
@@ -96,5 +113,3 @@ def get_workspaces():
 	with Connection() as conn:
 		conn.execute("SELECT * FROM Workspaces")
 		return [Workspace.from_query(conn, x) for x in conn.cursor.fetchall()]
-
-print(get_workspaces())
\ No newline at end of file
diff --git a/import_database.py b/import_database.py
index deceed40a826f436a7db3a2546563523db90b263..0bdd5d3b4cdd482f04f69decbd1dba0739345dff 100644
--- a/import_database.py
+++ b/import_database.py
@@ -1,6 +1,6 @@
 import database
 
-print(database.add_workspace(database.Workspace(
+workspace = database.Workspace(
 	"CodeBase",
 	"CodeBase Edinburgh, 37a Castle Terrace, Edinburgh, EH1 2EL",
 	"https://images.squarespace-cdn.com/content/v1/55439320e4b0f92b5d6c4c8b/1505921023376-PAHUDHVOOKIYF4XQPHOO/5951229048_3e3d50fcb1_o.jpg?format=750w",
@@ -11,4 +11,7 @@ print(database.add_workspace(database.Workspace(
 	"+44 131 560 2003",
 	"Monday - Friday, 9am - 5pm",
 	"Tramsched members should contact Hannah using the email address listed."
-)))
+)
+
+database.set_address_latlong(workspace.address, (55.9471623, -3.203928))
+print(database.add_workspace(workspace))
diff --git a/main.py b/main.py
index dc32f70e33060652797c6da10c685ca13c1bac44..d94babee53763417be976fbdc728d2a49aeb38da 100644
--- a/main.py
+++ b/main.py
@@ -1,5 +1,7 @@
 from flask import Flask, request, render_template
 import database
+import json
+import re
 
 app = Flask(__name__)
 
@@ -9,5 +11,13 @@ def home():
 		workspaces = database.get_workspaces()
 		return render_template("home.html", workspaces = workspaces)
 
+@app.route("/map", methods = ["GET"])
+def map():
+	if request.method == "GET":
+		workspaces = database.get_workspaces()
+		data = [{"id": x.id, "name": x.name, "address": x.address, "phoneNumber": x.phone_number, "email": x.email, "website": x.website, "latlong": database.lookup_address(x.address)} for x in workspaces]
+		dumped = json.dumps(data)
+		return render_template("map.html", json = re.sub(r"(?i)\</script\>", "<\/script>", dumped)) # escape </script>
+
 if __name__ == "__main__":
 	app.run(debug = True)
diff --git a/static/scripts/map.js b/static/scripts/map.js
new file mode 100644
index 0000000000000000000000000000000000000000..3ca7fbd11e7488ba01e7538ff96285eb2e7b83b7
--- /dev/null
+++ b/static/scripts/map.js
@@ -0,0 +1,27 @@
+var map = L.map("map").setView([54.004, -2.55], 5);
+
+L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
+	attribution: "&copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors"
+}).addTo(map);
+
+for (let workspace of mapData) {
+	L.marker(workspace.latlong).addTo(map)
+		.bindPopup(`<div class="popup"><div><a href="/workspace/${ encodeURIComponent(workspace.id) }" class="popup-title">${
+			escapeHTML(workspace.name)
+		}</a></div><div>Phone: <a href="tel:${ escapeHTML(workspace.phoneNumber) }">${
+			escapeHTML(workspace.phoneNumber)
+		}</a></div><div>Email: <a href="mailto:${ escapeHTML(workspace.email) }">${
+			escapeHTML(workspace.email)
+		}</a></div><div>Website: <a href="${ escapeHTML(workspace.website) }">${
+			escapeHTML(workspace.website)
+		}</a></div><div>${ escapeHTML(workspace.address) }</div></div>`);
+}
+
+function escapeHTML(html) {
+	let lookup = Object.create(null);
+	lookup["<"] = "&lt;"
+	lookup[">"] = "&gt;"
+	lookup["\""] = "&quot;"
+	lookup["&"] = "&amp";
+	return html.replace(/[<>"&]/g, v => lookup[v] || "");
+}
\ No newline at end of file
diff --git a/static/style.css b/static/style.css
index b9a1f7841e8337be3b320dfe301f41ca724ddbc7..099283c39bd291ca3fb9935f599ae1db27515911 100644
--- a/static/style.css
+++ b/static/style.css
@@ -127,3 +127,20 @@ nav li a:hover:last-child {
   color: #666;
   font-weight: 700;
 }
+
+#map {
+  height: 600px;
+}
+
+#map .popup {
+  font-family: CircularXX,sans-serif;
+  font-size: 0.8rem;
+  font-weight: 400;
+  line-height: 1.5;
+}
+
+#map .popup-title {
+  color: inherit;
+  font-size: 1rem;
+  font-weight: 500;
+}
diff --git a/templates/map.html b/templates/map.html
new file mode 100644
index 0000000000000000000000000000000000000000..af4c38439748711d2fda086f16c798fa2a859f14
--- /dev/null
+++ b/templates/map.html
@@ -0,0 +1,14 @@
+{% extends "main.html" %}
+{% block title %}Map{% endblock %}
+{% block mainBlock %}
+<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
+	integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
+	crossorigin=""/>
+	<!-- Make sure you put this AFTER Leaflet's CSS -->
+<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
+	integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
+	crossorigin=""></script>
+<script>var mapData = {{ json|safe }};</script>
+<div id="map"></div>
+<script src="/static/scripts/map.js"></script>
+{% endblock %}
\ No newline at end of file