Skip to content

Infogami

Infogami is the wiki framework that Open Library is built on top of. You'll see it mentioned throughout the docs, and understanding the basics will save you a lot of head-scratching when you're looking for "where does this route live?" and can't find a controller.

The Short Version

Open Library runs on a stack of three layers:

  1. web.py — a minimal Python web framework (similar in spirit to Flask). It handles HTTP requests, routing, and provides the web.ctx request context.
  2. Infogami — a wiki engine built on top of web.py. It adds the concept of typed pages, versioning, and a generic database layer.
  3. Open Library — the application code in this repository, which defines specific types (editions, works, authors) and all the features you see on the site.

Infogami lives in a separate repository at github.com/internetarchive/infogami and is included as a git submodule at vendor/infogami/.

The Two Things Infogami Does

1. It defines typed pages

Every URL on Open Library is an Infogami page, and every page has a type. You can see all the types at openlibrary.org/type. The important ones:

TypeWhat it representsURL pattern
/type/editionA specific book edition/books/OL...M
/type/workA logical work (all editions of a book)/works/OL...W
/type/authorAn author/authors/OL...A
/type/userA user account/people/username
/type/pageA generic wiki page (e.g. /about)/about

Each type has a schema that defines its fields. The base type classes (like Edition, Work, Author) are defined in openlibrary/core/models.py and then extended with Open Library-specific behavior in openlibrary/plugins/upstream/models.py. Both files register their classes with Infogami at startup.

2. It stores everything as typed objects

Infogami's database layer (called infobase) stores every object in two core PostgreSQL tables:

  • thing — one row per object, with an id, key (the URL path), type, and revision tracking
  • data — a JSON blob for each revision of each thing, keyed by thing_id and revision

There are also supporting tables for indexing common fields (datum_str, datum_int, datum_ref), versioning (version), transactions (transaction), and accounts (account). But the mental model is simple: every object is a row in thing with its full data as JSON in data.

How Infogami Routing Works

This is the part that confuses most newcomers.

Most routes you'll work with are defined explicitly by Open Library in openlibrary/plugins/. These have clear Python controller classes with URL patterns.

But pages that map to Infogami types (books, works, authors, wiki pages) are handled automatically by the Infogami engine. There is no explicit controller in the code. Instead:

  1. A request comes in (e.g. /books/OL1M/Foo)
  2. Infogami recognizes the URL matches a registered type (/type/edition)
  3. It fetches the object from the database
  4. It passes the object as page into the matching template at openlibrary/templates/type/{type}/view.html

So when you're wondering "where is the route for /books/...?" — there isn't one in the traditional sense. The route is implied by the type registration (see register_types() in core/models.py). The template is at templates/type/edition/view.html, and the page variable is an edition object whose properties are defined across core/models.py (base class) and plugins/upstream/models.py (extensions).

The Migration to FastAPI

Open Library is actively migrating away from web.py toward FastAPI. Here's what that means in practice:

  • New API endpoints go in openlibrary/fastapi/, not in openlibrary/plugins/. These use standard FastAPI patterns: Pydantic models for validation, dependency injection for auth, and explicit type annotations.
  • Old web.py endpoints are marked @deprecated("migrated to fastapi") but not removed until the FastAPI replacement is stable in production.
  • The Infogami wiki framework itself (typed pages, versioning, the thing/data schema) will remain for the foreseeable future. For now, you'll encounter both systems.

If you're building a new API endpoint, use FastAPI. See the FastAPI Migration guide for the workflow and patterns.

How to Query Data

From controllers, use web.ctx.site to fetch records:

python
doc = web.ctx.site.get("/works/OL5285479W")

keys = ["/works/OL5285479W", "/works/OL257943W"]
docs = web.ctx.site.get_many(keys)

For direct SQL against the feature tables (not the Infogami tables), use:

python
from openlibrary.core import db
oldb = db.get_db()
oldb.query("SELECT count(*) FROM bookshelves_books")

Where Things Live

WhatWhere
Type definitions (base classes)openlibrary/core/models.py
Type extensions (OL-specific behavior)openlibrary/plugins/upstream/models.py
Type registrationsopenlibrary/core/models.py
Infogami-type templatesopenlibrary/templates/type/
Plugin routes (web.py, legacy)openlibrary/plugins/
FastAPI endpoints (new)openlibrary/fastapi/
Reusable template fragmentsopenlibrary/macros/
Infogami source codevendor/infogami/

Learn More