- Static Site Generator: Hugo + TypeScript +
- Hosting: Cloudflare Pages
This project uses mise to manage tool versions (Node.js, Hugo, pnpm, precious, Dart Sass).
curl https://mise.jdx.dev/install.sh | shSee the mise installation guide for other installation methods.
mise trust # Trust the mise.toml configuration
mise install # Install all required tools (Node, Hugo, pnpm, etc.)
pnpm install # Install Node.js dependenciesYou should install our pre-commit hook. You can do this from your checkout
by running git/setup.sh. These hooks do things like ensure that the code you
commit is tidy and passes various linter checks.
The development server watches files, rebuilds the site, and reloads the browser when files change.
hugo serverThe static/_headers file is automatically generated from
bin/_headers.config.ts during the build process. Do not edit static/_headers
directly.
- Edit
bin/_headers.config.ts(the source of truth with readable format and TypeScript type safety) - Test your changes locally by generating the headers file:
pnpm run build:headers
- Commit only
bin/_headers.config.ts- the_headersfile will be generated automatically during deployment
The headers file is generated automatically during deployment via build.sh.
You can also generate it manually for local testing with pnpm run build:headers.
Each release note is its own content file. Create one with the release-note
archetype:
hugo new content --kind release-note geoip/release-notes/2026-01-15-geoip2-city-database-update.mdThe archetype fills in the title from the filename, stamps the current date and
time, and sets draft = false. The time component orders notes that are
published on the same day, so do not replace it with a bare date. If you create
two different notes in the same second, move the later one forward by a minute
so that the order is unambiguous.
Rewrite the generated title before you publish. Note titles use sentence case, but the archetype capitalizes only the first word of the slug, which is rarely the final wording you want.
Name the file <YYYY-MM-DD>-<slug>.md, where the date is the publication date
and the slug describes the note. The filename becomes the URL, so keep it
readable and do not change it after the note is published.
The date in the filename must match the date in the front matter. The archetype stamps the current date, so create the file on the day you publish it.
A note that applies to GeoIP and minFraud is two files, one in each product's
release-notes folder. Run the command twice with the same filename:
hugo new content --kind release-note geoip/release-notes/2026-01-15-web-service-maintenance.md
hugo new content --kind release-note minfraud/release-notes/2026-01-15-web-service-maintenance.mdThen copy the date value from the first file into the second. The two runs
stamp times that are seconds apart, and a shared timestamp keeps the note in the
same position in both listings and both feeds. You can then edit each copy
independently, for example to list the services that each product affects.
The description field is optional. It controls the preview card that Slack,
email clients, and search engines show for the release note. Without it, these
services usually show the opening of the release note body.
+++
title = 'Monthly GeoIP database diff report'
date = 2026-01-15T09:30:00-05:00
draft = false
description = 'Changes between the December and January GeoIP database releases.'
+++To do this, use the create-example-csv-zips-for-dev-site script in the
internal oneoffs repository.
In the markdown (mdx) file, add a description to the frontmatter located at
the top of the file:
+++
draft = false
title = 'GeoIP is the best'
description = 'GeoIP is the best IP Intelligence product suite ever made'
+++-
Add your image to the static/images directory.
-
In the markdown (mdx) file, add the path to the
imagekey in the frontmatter located at the top of the file. Do not includestaticto the path. For example, if your file is atstatic/images/geoip2-so-cool.gif, your frontmatter would look like:
+++
draft = false
title = 'GeoIP is the best'
description = 'GeoIP is the best IP Intelligence product suite ever made'
image = '/images/geoip2-so-cool.gif'
+++