Case study / Development & build workflows
Move between services.
Keep the workflow familiar.
Starting services and switching projects meant managing separate repositories, branches, dependencies, and setup steps. I proposed and led Volt’s monorepo migration, preserved the repository histories, and built the project environments and development workflows around it.
I observed fewer version conflicts and setup questions, easier project switching, and easier changes spanning services.
- Context
- Volt Labs / Multiple applications
- My contribution
- Migration, environments & workflows
- Team use
- Project environments, tasks & release builds
01 / Working across services
A change could begin with a tour of the repositories.
Starting multiple services was cumbersome. Developers had to keep track of which branch each separate repository was on, then deal with the dependencies and commands for the project they needed next.
Consolidating the repositories addressed part of that friction. Making the projects easier to work with also required explicit environments, consistent task commands, and a way to supply application configuration.
02 / Keeping the history
Bring the projects together.
Bring their history with them.
I proposed and led the migration into a monorepo. The migration procedure worked on temporary repository copies, relocated their files into project subdirectories, and merged the histories into the destination repository. The original remotes were left intact.
That retained the history behind the code while giving cross-service work a shared repository context. These were existing applications built by many engineers; my work was the migration and the platform workflows around them.
03 / A consistent way in
Let the project carry its development environment.
I built Nix environments and introduced just and Doppler. The whole engineering team used the project environments: enter with nix develop, then start the application with just run.
The Rust project flakes read their toolchain definition from the project and supplied the supporting libraries and build tools. This gave developers a defined environment when moving from one service to another.
The task runner supplied a consistent interface. Its shell ran through Doppler, loading configuration into the application’s process. Developers could use the task without manually reproducing that configuration-loading step.
Conceptual responsibilities / Development and release paths
Monorepo / Multiple projects
Project code + Nix environment + task commands
Doppler supplies configuration to task processes.
Local development
just run starts a project.devenv up coordinates local services.
Release build
Nix-provided toolchain
+ Zig cross-compilation
→ Linux release binary
04 / Linux release builds
I unplugged the dedicated build machine.
Make the build environment part of the workflow.
Previously, reliable production builds depended on a dedicated machine. I built the Zig cross-compilation workflow: the Nix shell provided the Rust toolchain, Zig, and cargo-zigbuild; the release task targeted x86-64 Linux with musl.
The team used the Nix/Zig Linux release-build workflow, and the dedicated machine was retired.
05 / Coordinating local services
Start the system together.
At the repository level, devenv coordinated application processes using their project task commands and included supporting local services. This addressed the other part of the original problem: bringing multiple services up together.
I used whole-system startup through devenv up.
06 / What I observed
Less friction between projects.
- Fewer version conflicts
- Easier switching between projects
- Fewer setup questions
- Easier changes spanning services
These were changes I observed in the team’s day-to-day work. The monorepo brought the code together; the environments and workflows made it easier to work across that code.
Start a conversation