Migrating JVM Microservices to a Rust Monolith with a Software Factory
How we used Pogon (our software factory), custom migration skills, and configurable workflows to preserve behavior while moving JVM services into a Rust modular monolith.
We set out to move our JVM microservices into a Rust modular monolith. We wanted the platform to handle more work with leaner infrastructure and our team to spend less time maintaining it.
The migration cut server costs by about 70% and gave us fewer deployments and a simpler CI process.
The platform ran on a microservice architecture. Business behavior was spread across APIs, background workers, databases, caches, and event streams. We chose a Rust modular monolith to improve throughput, reduce operating costs, and make changes easier to maintain. It would give us one deployable application with explicit business boundaries and shared infrastructure components.
The difficult part was getting there. A rewrite has to earn back the engineering time it consumes while preserving behavior that customers and other services depend on. That includes behavior nobody would choose when designing a system from scratch.
We used Pogon, our software factory, to make that work practical. We captured our migration approach in custom skills and configured workflows for implementation, checks, and code review. Engineers set the scope, reviewed the results, and made decisions at defined handoffs.
Here’s how we used a repeatable workflow to build a platform that’s easier to operate and maintain.
How we made the migration repeatable across multiple microservices
The platform runs as one process built from one Rust package. Each capability owns its business rules, application services, queries, mappings, and APIs. Shared modules handle reusable PostgreSQL, Redis, Kafka, and HTTP mechanics. The platform composes those pieces and manages the process.
That structure keeps related changes together. A business feature usually stays within its capability. Improvements to connection handling or transport mechanics go into shared modules. We avoid introducing frameworks for hypothetical future services; each migration brings concrete requirements.
We give the coding agents the same architectural guidance we expect engineers to follow. Repository instructions, architecture decisions, compatibility contracts, and test requirements form the working context. Pogon turns that context into an executable workflow: which agent performs each task, which skills it uses, which checks follow, and where a person must make a decision.
Those choices can vary by step. In Pogon, agent instructions are separate from the choice of model and coding harness. Work runs on compatible runners allocated to the project. That lets us keep our migration method consistent as the tools available to perform it change.
A skill captures a repeatable engineering procedure. In Pogon, skills have published versions, and a run records the exact versions it receives. When we update a skill, we can still see which instructions an earlier run used. A useful project skill can also be proposed to the organization library for reuse by other projects.
Our custom skills guide agents through understanding the existing behavior and implementing it in Rust. We review the proposed scope before implementation. The skills tell agents how to apply our engineering standards and verify the work.

Coordinate implementation and code review
Before each run, we establish the scope and acceptance criteria. Discovery work can produce a specification for review, while implementation proceeds from a specification we have already reviewed. The workflow defines the steps and where human approval is needed.
Pogon coordinates implementation, automated checks, and code review. Reviewers check that the changes preserve the required behavior and fit the platform's architecture. They also look for bugs. Agents address the findings and rerun the relevant checks before handing the work back to us.
Each run retains its workflow version, progress, and review results. Later edits to the workflow do not change an active run, and recorded progress allows execution to recover after a worker restart. We can see which changes were checked, what review found, and where work stopped.
Keep work moving between engineering sessions
Pogon is always running, so migration work can continue when engineers step away. Once we agree on the scope, agents can implement changes, run checks, and address review findings overnight. We return to inspect the changes and the evidence behind them.
That continuity is a practical benefit of a software factory. The workflow keeps its context and progress between engineering sessions. When it reaches a required approval or needs a product or architectural decision, it waits for our input.

Review the results
The handoff needs to answer a few practical questions:
- What changed, and which selected features does it implement?
- Which checks actually ran, and what did they establish?
- What did code review find, and how were those findings addressed?
- What remains blocked, uncertain, or dependent on a human decision?
We inspect the changes and supporting evidence, decide what to accept, and request revisions where necessary. Implementation approval does not automatically authorize a production deployment or a traffic switch.
Having the checks and review findings beside the changes saves us from reconstructing what happened during a run.
The workflow in practice
We started by turning our migration approach into custom skills, then used them to migrate the first service. Testing and reviewing that first implementation showed us where our instructions needed more detail.
We tested the migrated behavior, reviewed the code, and used what we found to improve both the implementation and the skills. Wherever an agent needed clarification or a reviewer caught a recurring issue, we looked for guidance that would help the next run avoid the same problem.
Then we migrated the second service with those revised skills and repeated the process. Each service brought its own requirements. By then, the steps from understanding its behavior to reviewing the implementation were better defined. We carried useful lessons forward while keeping service-specific decisions with the work they belonged to.
We saved those refinements as new skill versions in Pogon. The next migration used the updated instructions, and earlier runs kept a record of the versions they had used. Over successive migrations, we spent less effort explaining the process and could focus our review on the decisions unique to each service.
That cycle continued through the migration. Each completed service gave us working software and a better starting point for the next one.

What changed, and how we evaluate it
Capabilities that lived in separate JVM services now run in a single Rust application. They share infrastructure mechanics and development conventions.
We evaluate throughput, operating cost, and maintenance speed separately.
Fewer services and a smaller deployment
The migration made day-to-day operations simpler and leaner:
- Fewer services to run. Consolidating the migrated services into a Rust application gave us shared infrastructure components and fewer deployments to maintain.
- Simpler CI. One application gives us a common process for building, testing, and releasing changes.
- Lower infrastructure needs. Server costs fell by about 70%, and allocated production memory fell by 85.7%.
Throughput and latency
We measure successfully completed operations per second, latency percentiles, failure rates, and timeouts under comparable workloads. Resource settings, datasets, and background traffic need to be consistent for a useful before-and-after comparison.
We also account for background processing and queued work. A fast response only tells part of the story if the system is accumulating work elsewhere.
We want to know how much work the system can sustain while meeting its latency and failure requirements.
Operating cost
We want higher useful throughput per unit of infrastructure. That means looking at CPU and memory alongside database load, network traffic, and downstream processing.
Consolidation also changes the deployment footprint. We look at total infrastructure spend and cost per completed operation, alongside the resources needed to sustain the same workload. That keeps the comparison focused on the cost of running the whole system.
Maintenance speed
The new platform gives each capability a predictable structure, shared integration mechanics, and one set of quality requirements. The migration workflow gives engineers and agents a common way to define and verify changes.
The measure that matters is the time it takes to reach an accepted change, including our own review and any corrections.
Together, these measurements let us assess the migration against its original goals: more useful work per unit of infrastructure and less engineering effort to maintain and improve the platform.
What carries forward
The skills and supporting code from this migration are available for future work.
The next migration can reuse infrastructure components, test fixtures, architectural decisions, and the skills that define discovery and implementation. It starts with clearer expectations about what a specification must contain and what evidence a completed feature must provide.
We also learn where those instructions are insufficient. A missed compatibility requirement or a useful code-review finding can lead to a better test, a clearer contract, or a revised skill. Those improvements need review before becoming guidance for later work.
We keep those improvements in Pogon's versioned skills and shared workflow templates, where other projects can use them. Engineers review the results and update the guidance before it reaches the next migration. Each run retains the version it used.
We still choose the architecture and decide which behavior changes to accept. When the evidence conflicts or a service is ready for operational handover, engineers make the call. Agents handle implementation and verification within those decisions.
That is the value we want from a software factory. The effort we put into explaining a migration, defining its checks, and reviewing its results should make future work easier. Pogon gives that process a persistent home across tasks, projects, and coding tools.
During the migration, we used each run’s results to refine the next piece of work and the guidance behind it.
If you are working through a modernization project of your own, explore Pogon.