A IIIF server in Go. Implements the IIIF Image API 3.0, IIIF Presentation API 3.0, and minimal Auth/Search surfaces, with optional non-spec extensions for byte-stream transforms and uploads.
Designed as a replacement for resource-heavy JVM IIIF servers in container-first deployments. Single static binary, configured by a YAML file.
The Image API 3.0 surface is landed and exercised through the Docker-backed
make test path. Presentation 3.0 now includes manifest reads plus
annotation-page GET/PUT with text-granularity-aware validation. Search 2.0
has the HTTP surface and default no-op backend. Auth 2.0 has the
probe/access/token/logout surface with a default permit-all authorizer.
make build
./bin/triplet -config config.example.yamlmake build uses Docker via scripts/build.sh, so the default build path does
not require a host libvips installation.
Or with Docker:
cd deploy/compose && docker compose upmake test runs the suite inside Docker via scripts/test.sh. make build
does the same for the binary via scripts/build.sh. Both scripts mount or
reuse cached artifacts so repeated host runs do not start from scratch.
make test-integration starts the mariadb service from deploy/compose and
then runs the Docker-backed test suite with TEST_DSN; make test remains
deterministic and skips DB integration tests when no database is available.
make test-asan runs the same Docker-backed test path with Go's -asan
instrumentation for CGO-heavy checks.
make conformance runs HTTP-level IIIF smoke checks against a running server
and calls iiif-validate.py when that tool is installed.
Put TIFF/JP2/JPEG fixtures under fixtures/benchmark/, then run:
make benchmark-iiifThe benchmark builds the Triplet runtime image, starts it next to
islandora/cantaloupe:main, runs every request in
fixtures/benchmark/requests.tsv against every fixture image, and writes CSV /
JSONL output under results/benchmarks/<timestamp>/.
Useful knobs:
BENCH_IMAGE_DIR=/path/to/images \
BENCH_PASSES=5 \
BENCH_CONCURRENCY=4 \
BENCH_CANTALOUPE_IMAGE=islandora/cantaloupe:main \
make benchmark-iiifOutputs include request latency (requests.csv, summary.csv) and sampled
container CPU/memory (container-stats.jsonl, resource-summary.csv).
triplet is configured by a single YAML file. See config.example.yaml for the
full surface. Environment variables are not supported by design; if you need
templating, render the YAML before launch.
Current notable knobs:
vips.*tunes libvips startup,block_untrusted, and operation blocklists.iiif.search.*enables the Content Search 2.0 route with the default no-op backend.iiif.auth.*enables the Authorization Flow 2.0 route with the default permit-all authorizer.iiif.presentation.rootoriiif.presentation.dsnselects filesystem or MariaDB storage.sources.defaultcan befile,http, orgcs.cache.root/cache.bucket_urlconfigure derivative caching.cache.source_root/cache.source_bucket_urlconfigure HTTP source caching.
The IIIF Image API calls the original asset the identifier source and the
returned derivative the response image. Current format support:
| Format | Source / Input | Response / Output | Notes |
|---|---|---|---|
JPEG (jpg) |
Yes | Yes | |
PNG (png) |
Yes | Yes | |
TIFF (tif) |
Yes | Yes | |
WebP (webp) |
Yes | Yes | |
GIF (gif) |
Yes | Yes | GIF output is implemented in the pipeline. |
JP2 (jp2) |
Yes | Yes | JP2 source/input and response/output work when libvips has OpenJPEG. |
PDF (pdf) |
No | Yes | PDF response/output wraps the transformed raster as a single-page PDF. PDF source/input is disabled by default. |
deploy/cloudrun/— multi-region Cloud Run, mirrors thecantaloupe-cloudrunlayout.deploy/compose/— single-host docker-compose for self-hosters.
GCP is treated as a first-class target but no Google API leaks above the
storage abstraction. AWS/S3 is intentionally out of scope for this spike. The
runtime also exposes Prometheus metrics at /metrics.
Triplet now consumes machine-readable IIIF artifacts from
github.com/libops/iiif-spec instead
of owning local spec vendoring and schema generation tooling.
For Go code, triplet imports:
github.com/libops/iiif-spec/image/v3/gengithub.com/libops/iiif-spec/image/v3/schemagithub.com/libops/iiif-spec/presentation/v3/gen/...
Triplet’s local types/ packages are thin aliases or wrappers on top of those
imported wire types where the server needs stable names or extension fields
beyond the upstream schemas.
Triplet also tracks extension support in code and tests. In particular, the Presentation annotation path validates the IIIF Text Granularity extension, and the Search 2.0 route exposes a default no-op Content Search surface.
MIT — see LICENSE.