Back to blog
2026-09-15 Thijs Creemers

Release: v1.0.0-rc-1 — the release candidate, and the breaking list is closed


The release candidate for 1.0.0. Three breaking changes ship here, they are exercised in this release first, and that is the complete list — nothing further lands as Breaking before the 1.0.0 tag. Deprecations are deferred to 2.0, so what warns today keeps working.

If you are running a beta in anything you care about, this is the release to move to. Two of the fixes are security fixes in the storage module, and the upgrade notes at the bottom are longer than usual.

Breaking: three changes

:wagoe/user-http-handler is removed. It has thrown on init since it was deprecated, so nothing was running on it — use :wagoe/user-routes with the top-level :wagoe/http-handler.

Ten methods are dropped from the user repository ports. None of them had a caller. If you implement the ports by hand, delete them; wagoe.user.ports lists what remains.

An unknown :provider on :wagoe/cache or :wagoe/realtime now throws. It used to fall back to an in-process adapter, which is the worst possible failure: a typo in production ran a node-local cache or a node-local event bus across your cluster, and nothing said so.

Deprecated: one provider vocabulary

Provider names were three vocabularies wearing one keyword. They are now :memory and :redis everywhere, and :db where a module has one. :in-memory, :redis-streams and :database warn until 2.0.

wagoe.jobs.shell.adapters.db/enqueue-in-tx! is deprecated — call wagoe.jobs.ports/enqueue-in-tx! on the queue component. The :wagoe/admin and :wagoe/auth-user-repository Integrant components are deprecated too; drop them from hand-written wiring, and keep :wagoe/admin in :active, which is still the module switch.

Fixed: two ways local storage could be abused

The local storage adapter let a caller escape :base-path. A key containing ../, or a symlink under the root, could read, write and delete outside it. Upgrade if you accept storage keys from users.

Signed download URLs were never verified. The route served the file without checking expires or signature, so a signed URL was a suggestion. It enforces both now; point :http-base-path at wherever you mount the routes. Those routes can also be mounted deliberately with :expose-http? true — they carry no authorization of their own, so the mounting application has to guard them.

Fixed: modules you could enable but not run

Nine modules were documented, published, and absent from a generated project’s deps.edn — jobs, events, push, realtime, reports, calendar, geo, audience and email. They ship in it now. Around that, the modules themselves:

  • Audience could not boot. IUserDataSource had no implementation and nothing wired the service. It segments your users table now. Saved segments and compositions also resolved to the wrong users, because filters lost their keywords through JSON; audiences ran on H2 only; and its cache never hit, so every resolve recomputed.

  • Scheduled pushes were never delivered. schedule-push! enqueued into a nil queue with no registry holding its handlers. Enable :wagoe/jobs and both are wired.

  • Configured APNs push never reached Apple. The generated config wrote :key-file where the code reads :key-path, and half-configured push fell back to the mock in silence. It now refuses to boot instead.

  • wagoe add push created no tables — its migrations ship a manifest, so bb migrate up finds them. wagoe add reports and wagoe add calendar switched nothing on at all: both had an empty config snippet, so the library landed in deps.edn and :active stayed untouched.

  • Email’s queued mode was documented and never built. :wagoe/email-queue ships over the sender you configured. Configured FCM push no longer throws at boot either — set :fcm-credentials {:project-id … :credentials-path …}.

  • service <module> now works for nine more modules, and service tenant and service push answer over RPC. Every other service records why it offers nothing remote rather than leaving the question open.

Fixed: Java 21 is the baseline everywhere

The production image built and ran on JDK 17 while the installer demanded 21. One baseline now — Java 21 — held by a gate that reads the package names people actually install. Rebuild your images.

Fixed: your database session ran in the host’s timezone

Every alias and launcher sets -Duser.timezone=UTC, so zone-less columns re-read in UTC instead of in whatever the host was set to. Push, geo and audience timestamps carried no timezone at all; a migration widens them on PostgreSQL and H2, and it assumes the stored values are UTC.

MySQL sessions also ignored their timezone and charset settings — a sql_mode MySQL 8 rejects aborted the rest of the session setup.

Fixed: adapters that could not connect

MySQL could not open a connection and SQLite reported every table as absent; SQLite was also handed PostgreSQL column types. Upgrade if you run either.

The S3 adapter threw on every S3-compatible endpoint, so MinIO, Spaces and the like could not be used despite being named as supported. Set :endpoint and it works.

Added: libraries carry a stability tier

Eight libraries are marked incubating: published, usable, and outside the breaking-change guarantee. wagoe list modules shows the tier, and so do the library pages. Knowing which eight matters more at a release candidate than at any point before it.

Expired sessions are now pruned — :wagoe/session-pruner deletes them 30 days after expiry; set :enable-pruning false to keep the rows. And worker mode actually runs jobs: enable :wagoe/jobs {:provider :memory}, modules contribute handlers, and :workers {:count 0} gives you a web-only node.

Fixed: deployment blueprints that deployed nothing

The Render and Fly blueprints built a container that served nothing. Both build the root Dockerfile now and set ERROR_REPORTING_PROVIDER=no-op. The dev image ignored its own JAVA_OPTS-Xmx512m never applied and it ran on 1960MB; rebuild if you use resources/conf/dev/Dockerfile.

Changed: dependencies, and knowing when they drift

34 coordinates across 34 deps.edn files are up to date, jedis 8 and the Google Cloud bundle among them. Re-pin if you override any. bb upgrade-outdated was also under-reporting drift: it read an index that lags, which hid the H2, MySQL, PostgreSQL and SQLite drivers, and it no longer offers prereleases.

Two build-side fixes worth naming because they affect what you get: a locally built library jar could carry a previous build’s namespaces — jar cleans first now, and the published artifacts were checked and are unaffected. And a pre-release could again outrank the release it precedes; pre-releases are cut from the next minor, and both bb bump and the publish guard refuse a patch pre-release.

Removed

docs-site/ is gone — the published site is built from the same .adoc sources, and this was a second renderer nothing ran. The per-engine query, metadata and utils namespaces under adapters.database are removed along with config-factory; build adapters with factory/db-context.

Version alignment

All 31 artifacts bumped to v1.0.0-rc-1 to maintain lockstep versioning.

Upgrade

Re-run the installer to pick up the latest release:

curl -fsSL https://get.wagoe.org | bash

Coming from a beta, work through this list:

  1. Rebuild your images. Java 21 is the baseline; a JDK 17 image is no longer supported.

  2. Replace :wagoe/user-http-handler with :wagoe/user-routes plus the top-level :wagoe/http-handler, and drop :wagoe/admin and :wagoe/auth-user-repository from hand-written wiring.

  3. Check every :provider. An unknown one throws at boot now instead of quietly running in-process. Rename :in-memory to :memory, :redis-streams to :redis, and :database to :db.

  4. Delete the ten dropped methods from any hand-written user repository port implementation.

  5. Run bb migrate up. The push, geo and audience timestamp migration assumes the stored values are UTC — check that before you run it if your host was not.

  6. Re-pin any dependency you override, and upgrade if you accept user-supplied storage keys or serve signed storage URLs.