Melange v0.10.1
Melange v0.10.1 makes melange migrate safe to run on every application startup: concurrent runs are serialized, and an older melange no longer overwrites functions generated by a newer one. The CLI now warns when it, or the functions deployed in your database, are covered by a published security advisory. Windows users can install with Scoop, and each release is now checked by installing it through every channel.
Upgrading
v0.10.1 changes no generated SQL and no Go or TypeScript runtime APIs. Running melange migrate is optional.
The downgrade guard described below only runs in melange v0.10.1 and later. During the rolling deploy that brings in v0.10.1, replicas still on v0.10.0 can still re-apply their functions, as before. From the next upgrade on, every replica has the guard.
If a startup script runs melange migrate && ./app, read exit code 5 before your next upgrade.
Safe concurrent migrations
The docs recommend running melange migrate when your application starts, but concurrent runs were unprotected:
- On a fresh database, replicas starting together could fail with a unique-violation (
23505) while racing to createmelange_migrations. - During a rolling deploy, a replica still on the old version saw a newer codegen version, re-applied its older generated SQL over the upgraded functions, and undid codegen fixes. Old and new replicas then kept overwriting each other as they restarted.
Every migration now takes a transaction-scoped advisory lock on the target schema before touching the tracking table. Under the lock it re-reads the latest migration record, so the first replica applies and records the migration and the rest see that record and skip. The lock uses PostgreSQL’s two-key form, so it cannot collide with your application’s own single-key advisory locks.
Refusing downgrades
migrate now refuses to replace functions generated by a newer melange:
Error: migration refused: database functions were generated by melange 0.11.0, newer than this melange (0.10.1); nothing was applied (upgrade melange, or force the migration to downgrade deliberately)The refusal exits with code 5. The newer functions keep the same SQL API, so an older replica can keep serving, and a startup script can treat code 5 as success:
melange migrate || [ $? -eq 5 ]Code 5 is non-zero on purpose: melange migrate && ./app stops an old replica instead of silently skipping. Pass --force to downgrade deliberately. Builds whose versions cannot be ordered are never refused: dev builds and local git describe builds such as v0.10.0-3-gabc1234.
Go users of pkg/migrator get the same lock and guard. A refusal returns *migrator.DatabaseAheadError.
The guard compares codegen versions only. An old replica with an older schema but the same melange version still re-applies its schema; --if-deployed-checksum covers that case. See Concurrent migrations and downgrades.
Security advisory warnings
Dependabot and govulncheck only see Go modules listed in a go.mod. They miss a CLI installed with Homebrew, Scoop, a package or go install. They also miss a database whose generated functions predate a fix: upgrading the CLI clears the alert, but the functions stay vulnerable until melange migrate regenerates them.
The background update check now also fetches the repository’s published security advisories and caches them alongside the version check:
- CLI: when the running version is covered, a warning listing each advisory appears above the update notice.
melange doctor: warns under Deployed Model when the melange version recorded with the deployed functions is covered, and tells you to upgrade and runmelange migrate.melange status: adds a Security line, and anadvisoriesfield to--format json.
Advisories follow the update check’s rules: off in CI and with --no-update-check, and cached for 24 hours. A slow or failed advisory fetch delays the update notice by at most half a second. doctor and status wait up to three seconds for it, then skip the check.
Installation and updates
Scoop on Windows:
scoop bucket add pthm https://github.com/pthm/scoop-bucket scoop install pthm/melangeThe right update command. The update notice now prints the command for how you installed melange:
brew upgrade pthm/tap/melange,scoop update melange,go install github.com/pthm/melange@latest, or a link to the update instructions. It used to suggest Homebrew orgo installto everyone.Floating Docker tags. Images are also tagged
vX.Y, which follows patch releases:ghcr.io/pthm/melange:v0.10. AvXtag will start at 1.0.Build provenance. Release archives, packages,
checksums.txtand the container image carry GitHub attestations. Check them withgh attestation verify <file> --repo pthm/melange.Tested installs. After each release, CI installs the new version with Scoop on Windows, Homebrew on macOS, and the
.deband container image on Linux, then checks thatmelange versionreports it.Update-check cache location. The cache now lives in the operating system’s cache directory:
%LocalAppData%on Windows and~/Library/Cacheson macOS, rather than~/.cacheeverywhere.XDG_CACHE_HOMEstill overrides it. The old~/.cache/melangedirectory on those systems can be deleted.
The installation guide is reorganised by platform, covers every channel, and has a section on the Go and TypeScript client libraries.
Fixes
- No stray characters on your prompt. Every command used to query the terminal’s background colour, and a reply that arrived after a short command exited was echoed onto the shell prompt. Only the interactive
melange initwizard queries it now. - Consistent colour.
doctorandstatusare now coloured likeexplainandexpand, and every command follows the same rules: plain when output is piped, andNO_COLOR,CLICOLOR_FORCEandTERM=dumbare respected. melange initon Windows wrote the config path intoAGENTS.mdwith a backslash (melange\config.yaml). Paths in the agent instructions now always use forward slashes, since the file is committed and read on every OS.
Documentation
- Replacing Conditions: Melange rejects OpenFGA conditions, but most can be expressed another way. Conditions on stored data (expiry, status) become a
WHEREclause inmelange_tuples. Request-only data becomes contextual tuples. Request data compared with stored data goes through a transaction-local setting read by the view. - The Performance reference is rebuilt on measurements from Cloud SQL, with check latency split into database and network time, and list costs by query shape. Earlier figures were local, and mostly measured Docker networking.
- Docs pages and release posts have a copy menu that copies a page’s Markdown or opens it in Claude or ChatGPT.
Try it out
# Upgrade the CLI
brew upgrade pthm/tap/melange # Homebrew
scoop update melange # Scoop
go install github.com/pthm/melange@v0.10.1
# Or pull the container image
docker pull ghcr.io/pthm/melange:v0.10.1See the installation guide for every channel.
Feedback
Open an issue for bugs or feature requests, and report security issues through private vulnerability reporting.
