Effect · Teams & adoption
Adopting Effect without leaving the team behind
Where I’d start, what I’d teach first, and how I’d tell whether the change was helping.
The team still has a product to ship.
I’m very fond of functional programming. That isn’t, on its own, a reason to change a team’s stack.
If a CTO asks me about Effect, I want to understand what has become difficult. Unclear failure handling? Tests that need half the application running? Background work that outlives the request that started it?
Those are useful starting points. “Let’s rewrite everything” is a fairly expensive way to find out whether people like a library.
Choose one awkward boundary.
I’d start with a contained feature that already needs attention. A supplier integration is a good candidate: external data, a few expected failures, and behaviour I can test independently.
I’d keep the existing application around it. At the boundary, Effect can run through a Promise-based interface. Inside the feature, I keep the work composed as effects rather than repeatedly switching between the two.
For long-lived services such as connection pools, I’d manage their lifetime at the application boundary. ManagedRuntime can provide shared services and release their resources when it is disposed. I wouldn’t create a new pool for every request.
I’d also agree what success means before starting. For this feature, that might be a testable timeout path and enough context to diagnose a failed import without guessing.
Teach the feature before the vocabulary.
I’ve mentored teammates in TypeScript and functional programming. I like starting with code they already need to change. There’s less to hold in your head when the business problem is familiar.
With Effect, I’d first read a signature together:
import type { Effect } from 'effect';
type ImportError = { readonly _tag: 'SupplierUnavailable' } | { readonly _tag: 'InvalidCatalogue' };
type ImportCatalogue = Effect.Effect<number, ImportError>;This simplified operation returns the number of imported items, or one of two expected failures. A service requirement can appear as the third type parameter when the operation needs one supplied.
Then I’d make a small change together: handle an unavailable supplier differently from an invalid catalogue. Once that feels familiar, services and Layers have a concrete purpose. Services describe the dependencies. Layers describe how to construct them, including any resources they need.
Nobody needs a category theory detour to fix the import.
Make the next change easier for someone else.
I’d leave one complete example with input decoding, named failures, a test implementation of the dependency, and the caller’s response.
Then I’d pair on a second change with the teammate driving. If they keep needing me to explain the same abstraction, I’d simplify it or improve the example.
Coding agents can help explain unfamiliar code, but I’d check their explanation against the installed version and a working test. I don’t want someone learning an API that only exists in the chat.
Make the version decision deliberately.
As of September 2026, Effect v4 is in its release-candidate phase. I’d treat adopting Effect and migrating an existing v3 application as separate decisions.
For a team already shipping on v3, I’d check the migration effort and ecosystem compatibility before adding a version change to the same piece of work. For a new project, I’d assess the current v4 release against the actual dependencies and deployment needs.
I’d also call out any effect/unstable modules being used. Their compatibility contract differs from stable modules, so the team should know which upgrades need closer review.
Decide together whether to go further.
After the first feature, I’d ask the people maintaining it: are failures easier to understand? Are tests easier to set up? Can someone else make a change without waiting for me?
If it helps, I’d expand from there. If it adds more ceremony than clarity, I’d revisit the design before spreading it.
I want to leave the team with software they feel comfortable owning. Preferably with one fewer person they have to interrupt to get something done.
Start with a real problem and teach through the feature. Adoption is working when another teammate can change it confidently without waiting for the Effect enthusiast.
Working on something similar?
Get in touch