finds.dev

public digest · 5 picks

Self-host your stack: bookmarks, brokers, caches, and Rust on the web

A theme emerged in this week's picks without us planning it: taking back control of infrastructure you'd otherwise rent. A bookmark manager that actually keeps the content. A Turborepo cache server you run yourself. A message broker that predates Kafka and still earns its place. The thread connecting all of them is that someone sat down and did the unsexy work — protocol handling, storage abstraction, migration tooling — so you don't have to.

We also have two picks that are less about ownership and more about foundations: a Spring Boot test library that handles the container lifecycle problem most teams solve badly, and wasm-bindgen, which is simply the reason Rust-in-the-browser is possible at all. If any of these have been on your radar, this is a good week to actually read the source.

// pick 1 of 5

karakeep-app/karakeep

Karakeep is a self-hosted bookmark manager that stores links, notes, images, and PDFs with LLM-based auto-tagging, full-text search via Meilisearch, and full-page archival. It targets developers and homelab users who want a Pocket/mymind replacement they actually own. The feature surface is broad: browser extensions for all three major browsers, iOS/Android apps, RSS hoarding, OCR, yt-dlp video archiving, and a rule engine.

The core insight here is the right one: a bookmark manager that only saves URLs is a list of 404s waiting to happen. Karakeep does full-page archival and yt-dlp video capture, so what you save stays saved. The rule engine for automated tagging and organization is a genuine step above 'add a tag manually and forget', and the MCP server plus CLI mean you can wire this into agentic workflows without screen-scraping.

The tech choices are honest about the tradeoffs. Using Meilisearch instead of rolling their own search index is the right call, but it also means this isn't a 'one container and done' deploy — Meilisearch is a hard dependency, which raises the ops floor. The LLM integration is classification and tagging, not semantic/embedding search, so keyword search is what you're actually getting across large collections.

What to know going in: the project was called Hoarder until recently, so old tutorials, Docker image names, and community posts will use the wrong name. If you're following a guide from six months ago, expect some friction. AGPL-3.0 is also load-bearing here — fine for personal use, relevant if you're thinking about embedding this in anything commercial.

View on GitHub → Our full take →

// pick 2 of 5

PlaytikaOSS/testcontainers-spring-boot

A Spring Boot auto-configuration library that spins up 35+ stateful services (Kafka, Redis, PostgreSQL, Cassandra, Keycloak, etc.) via Testcontainers during the bootstrap phase, exposing connection properties so your app wires up without any extra code. It's aimed at Spring Boot teams who want real integration tests without managing containers manually. Maintained by Playtika and actively tracking Spring Boot 4.0.

The specific problem this solves well is timing: getting real service containers available before Spring's bean wiring phase, so your DataSource or KafkaTemplate actually connects to something. Doing this yourself with @DynamicPropertySource and lifecycle callbacks is doable but fiddly, and this library handles the ordering correctly. The global `embedded.containers.enabled=false` escape hatch for CI environments without Docker is a small but important detail.

The breadth of supported services is the headline number — 35+ including things like SpiceDB, VoltDB, and Vertica that you'd otherwise be writing custom glue for. For teams with heterogeneous stacks, that coverage is real value.

Heads up: if you're on Spring Boot 3.1 or later, check whether `@ServiceConnection` covers your services before adopting this. Testcontainers' own Boot integration has caught up for the mainstream cases, and you may be pulling in a Spring Cloud bootstrap dependency for services you could handle natively. Also worth knowing: this library is fairly niche by the numbers, so for the more obscure service adapters, the maintainer response time on bugs is an open question.

View on GitHub → Our full take →

// pick 3 of 5

apache/artemis

Apache ActiveMQ Artemis is the successor to HornetQ — a mature, multi-protocol message broker that speaks AMQP 1.0, MQTT 3.1/5, STOMP, OpenWire, and JMS. It's the embedded broker in WildFly/JBoss EAP and the drop-in replacement for the original ActiveMQ Classic. If you need a battle-tested JVM broker for enterprise messaging without Kafka's operational weight, this is the default answer.

The real case for Artemis is protocol breadth at one address: JMS, AMQP, MQTT, STOMP, and OpenWire all on the same broker without bridges. If you have a Java backend doing JMS, an IoT device fleet speaking MQTT, and a Ruby service using STOMP, Artemis handles all three without you running separate brokers or writing protocol translators. That's a genuine operational win.

The built-in `artemis perf` CLI with microsecond-resolution latency histograms is also worth calling out — it's the kind of tool that's usually missing from broker projects and is genuinely useful for capacity planning before you go to production.

The GitHub star count is misleading: most people using this consume it as a transitive dependency through WildFly, JBoss EAP, or Quarkus and never visit the repo. It's more widely deployed than 1026 stars suggests. What to know: the XML configuration gets unwieldy fast, there's no sane modularization story for `broker.xml`, and the management console looks and feels like enterprise Java circa 2015. If your team lives in reactive streams, there's no first-party reactive client — you're wrapping blocking JMS calls yourself.

View on GitHub → Our full take →

// pick 4 of 5

ducktors/turborepo-remote-cache

A self-hosted implementation of Turborepo's remote cache API, so you can run your own cache server instead of paying Vercel. It's a Fastify app that speaks the Turbo cache protocol and backs it with whichever storage you already have — S3, GCS, Azure Blob, local disk, or MinIO. Teams running Turborepo on-prem or in air-gapped environments will find this is the only real option.

Turborepo's remote cache is valuable, but paying Vercel for it when you're running everything else on your own infra is an annoying tax. This is the alternative: a Fastify app that speaks the same protocol, backed by whatever storage you already have. The storage abstraction covers S3, GCS, Azure Blob, MinIO, and local disk as genuine first-class options, not bolted-on afterthoughts, and the tests run against each provider separately.

The deploy story is unusually well thought out for a project this size — Docker image, Lambda handler, Cloud Run docs, DigitalOcean one-click, and a Vercel adapter all exist. That covers most of where people actually run Node services.

The main thing to know going in is that the Turbo cache protocol is reverse-engineered — Vercel doesn't publish a spec — which means a Turborepo update can silently break compatibility. Watch the issue tracker after major Turbo releases. Cache eviction is also your problem: for object storage backends, you configure S3/GCS lifecycle rules yourself, and there's no hit-rate or cache-size observability built in, so you're guessing at whether it's actually helping your CI times.

View on GitHub → Our full take →

// pick 5 of 5

wasm-bindgen/wasm-bindgen

wasm-bindgen is the foundational glue layer for Rust-to-WebAssembly interop — it generates the JavaScript bindings that let Rust code call browser APIs and JS code call exported Rust functions. If you're shipping Rust to the browser, you're almost certainly using this. It's maintained by the official Rust and WebAssembly Working Group and has been the de facto standard since 2018.

If you're shipping Rust to the browser, this is the layer that makes it work. The binding generation is genuinely lean — it statically traces which browser APIs you actually import and only emits glue for those, which matters for bundle size. TypeScript definitions come out automatically alongside the JS bindings, so the JS side of your project gets type safety for free. The Rust async to JS Promise bridge via wasm-bindgen-futures is clean and the abstraction doesn't leak badly.

The reference test suite is worth mentioning specifically: hundreds of snapshot triples pairing Rust source with expected JS and TypeScript output, which means regressions in generated code surface immediately rather than showing up as mysterious runtime failures in your app.

The CLI-library version mismatch problem is the thing that bites everyone on first upgrade and on every upgrade after. The error message when they don't match is unhelpful at best, a panic at worst — budget time for this. The web-sys API surface is machine-generated from WebIDL and calling a single DOM method can require enough `.unchecked_ref()` casts and variant hunting that you'll instinctively reach for the raw JsValue escape hatch more than you should. Multi-threaded Wasm (Workers, SharedArrayBuffer) is still second-class and requires external crates or manual postMessage wiring.

View on GitHub → Our full take →

That's the week. If you want these picks in your inbox before they hit the site, the email signup is at the bottom of the page — no noise, just the digest.

Get this in your inbox →