Node: running several services locally
Node makes the first two services easy: npm start twice and you are
working. The trouble arrives with the fourth terminal, the second service that also
wants port 3000, and the package you are changing at the same time as the service
that consumes it.
What breaks first
- The terminals. One per service, each with its own environment, and no memory of which combination worked yesterday.
- The ports. Everything defaults to 3000. You end up with a
.envper developer that never gets committed and never gets documented. - The service URLs. Every
fetchto another service reads a variable, and pointing three of them at the shared environment means editing files you must not commit. - The local package.
npm linkworks until it does not: duplicated dependencies, a hoisted copy that wins, and a resolution that behaves differently from the published one. - Nobody waits. Your service starts, calls the one that has not finished booting, and the error looks like a bug in your code.
What Aseptic does
Aseptic autodetects a Node service —or an Angular front end— from its
package.json, starts it as a native process with your own script, and
passes configuration in as environment variables at startup. The URLs between
services are rewritten there, so no .env in your repository has to
change and there is nothing to forget to revert.
A scenario is the set of services in a flow, started in dependency order, waiting on health rather than on a process. Colliding ports are remapped and the remapped value is what the callers receive. If the flow needs Kafka, Redis or PostgreSQL, Aseptic brings them up in Docker and manages them — your services stay off Docker unless you want them containerised.
Each dependency resolves where you choose: a local service you have open, the shared cloud environment, or a mock. Per dependency, changeable mid-afternoon.
Local packages, without npm link surprises
If you are changing a package of your own and the service that consumes it at the
same time, Aseptic builds the package and links it into the consumer's
node_modules, where Node actually resolves it, and can rebuild and
relink as you save. It does not edit the consumer's package.json, and
unlinking undoes only what it put there. The same mechanism covers Maven, Gradle and
Python for teams whose systems are not all JavaScript.
What it does not do
It does not replace your scripts, your bundler or your test runner: it calls them. It does not run a Kubernetes cluster, so anything you need to verify at that level belongs to a different tool. It needs Docker installed for the shared infrastructure.
It is in public beta, ships for Windows, macOS and Linux, and it is free for personal use.
Next to the alternatives
If your services are already images and you deploy them with manifests you maintain, Tilt or Skaffold keep the local loop shaped like production, at the price of a build on every change. The alternatives to Docker Compose page covers the whole field.
There are equivalents of this page for Spring Boot and for Quarkus.
Frequently asked questions
Why do npm scripts stop working with several services?
Because they do not scale past the fourth: a terminal per service, remembering the startup order, and the URLs between them ending up in environment variables copied by hand on every machine.
Do I need Docker images of my Node services?
No. Aseptic starts them as processes with their own command; Docker is used for the shared infrastructure.
How do I link a local package without publishing it to npm?
Aseptic builds it and links it into the node_modules of whoever consumes it, and can rebuild and relink on the fly when it changes. It is reversible: unlinking undoes only what it put there.