The Who's On First Spelunker Codebase

The Who's On First Spelunker codebase is broken up in to three parts:

  1. go-whosonfirst-spelunker
  2. go-whosonfirst-spelunker-{DATABASE}
  3. go-whosonfirst-spelunker-httpd


This package defines a common interface (sometimes called a contract in other programming languages) for how the Spelunker works. It defines the kinds of questions (methods) you can ask it and what the responses to those questions will look like. It does not actually implement any functionality.

A note about versioning

Currently all of the go-whosonfirst-spelunker-related packages are unversioned reflecting the fact that they are still in flux. The rate of change is slowing down and each will eventually be assigned version numbers less than 1.x for as long as it takes to produce the initial "minimal viable (and working)" Spelunker implementations. These versions (0.x.y) should not be assumed to be backwards compatible with each other and are expected to change as the first stable interface is settled, specifically if and whether it will contain spatial functions.

Once a decision has been reached on that matter and everything is proven to work this package (and all the related packages, discussed below) will be bumped up to a "version 2.x" release, skipping version 1.x altogether, reflecting the fact that the original Python version of the Spelunker is "version 1" and that this code base is meaningfully different.

After the "v2" release this package (and related packages) will follow the standard Go convention of incrementing version numbers if and when there are changes to the underlying Spelunker interface.


These packages are implementations of the go-whosonfirst-spelunker interfaces. As a practical matter this tends to mean that it is the code which manages how the questions and answers defined in the spelunker inteface are stored and retrieved from a particular database engine. For example:

Each go-whosonfirst-spelunker-{DATABASE} package provides code and applications specific to its implementation. By definition no two implementations will implement the underlying "spelunker" interface the same way and each will have its own trade-offs.

Some will be easier to run locally with small datasets with performance costs that are fine for development work but not production traffic. Others are geared towards a production environment but which require non-trivial configuration and set up costs. Both of these are valid use cases and the goal of the "v2" Spelunker is to be able to support each of them which is why the code base has been split up in to three parts.

Each package imports the code from the go-whosonfirst-spelunker package and MAY import code from the go-whosonfirst-spelunker-httpd package, discussed below.


This package implements the actual Spelunker web application. These are the web pages that humans can look at and interact with and the web "resources" that machines and robots (including the Spelunker web application itself) can consume data from. For example, this is the package that renders the page you are currently looking at.

The thinking here is to separate the Spelunker "interface" and the implementation of that interface from the Spelunker application itself. In that way the code in this package (go-whosonfirst-spelunker-httpd) is like a kind of interface in that by default it doesn't actually do anything. Concretely it will run but the default Spelunker implementation it uses is the NullSpelunker package which simply returns "Not implemented" for every method defined by the Spelunker interface.

It is assumed that database-specific implementations of the Spelunker interface will also provide a "server" application that, under the hood, imports the core of the Spelunker application from go-whosonfirst-spelunker-httpd and then supplements that code with its own specific logic.

For example, here is what the code the "server" application in the go-whosonfirst-spelunker-opensearch package looks like:

package main

import (

	_ ""

func main() {
	ctx := context.Background()
	logger := slog.Default()
	server.Run(ctx, logger)


A detailed How to section explaining how to configure and run both the OpenSearch and SQLite flavoured Spelunker applications is in progress and will be published shortly.