Migrate 50 Files from REST to GraphQL
Scope a 50-file REST-to-GraphQL migration, split it into conflict-free work packages, and run them in parallel.
Scope the migration surface
Connect GitHub and Postman. Use Postman to inspect the GraphQL operations already available, and GitHub to read the code. Opulent starts by mapping which files import the legacy REST client and how they cluster by domain.
The migration follows a playbook, a reusable, named set of steps Opulent follows per package. It defines the exact import swap, call rewrite, error-handling change, and test update so every PR looks the same.
Playbook: !rest-to-graphql
For each file in the package:
1. Replace import { restClient } from "src/lib/restClient" with
import { graphqlClient } from "src/lib/graphqlClient".
2. Rewrite each REST call to the matching GraphQL operation in
src/graphql/operations/.
3. Update error handling from HTTP status codes to GraphQL error
types (see src/lib/graphqlClient.ts for the error map).
4. Update the test file: replace REST mocks with GraphQL mocks
(msw) and assert on the operation name, not the URL.
5. Run npm run typecheck && npm test -- --related.
6. Open a PR titled: "migrate: [domain] REST -> GraphQL".
Stop if a file is imported by another package; flag it for the
scheduler.Before parallel runs, ask Opulent to find the dependency graph and flag files that share mutable state or import each other. Migrating a shared file in two packages at once creates merge conflicts.
Build independent work packages
Opulent proposes a grouping of files by domain and estimated complexity. Each group should be self-contained: no shared files, no dependency on another group's work, and no overlapping test fixtures.
Approve the grouping before launching. If a domain depends on another (Admin depends on Auth middleware, for example) schedule them sequentially, not in parallel.
Proposed work packages (8 groups, 50 files): Group 1, User Management (7 files, complexity M) Group 2, Billing (9 files, complexity L) Group 3, Analytics (5 files, complexity S) Group 4, Auth (6 files, complexity L) -> migrate first Group 5, Notifications (8 files, complexity M) Group 6, Admin (5 files, complexity M) -> depends on Group 4 Group 7, Search (4 files, complexity S) Group 8, Onboarding (6 files, complexity M) Launch 6 groups in parallel; run Auth first, then Admin.
Run each package in parallel
Opulent spawns one run per package. Each run executes the migration playbook on its assigned files, runs typecheck and tests, and opens a separate PR. Parallel packages keep the wall-clock time close to one package instead of the whole 50 files.
The scheduler tracks dependencies: Auth merges before Admin starts, and any package that fails a test blocks its dependent packages until the issue is fixed.
Run package: Billing (9 files) Actions: - Rewrote 9 imports and API calls to GraphQL operations. - Updated error handling to GraphQL error types. - Replaced REST mocks in 6 test files with msw GraphQL mocks. - Ran npm run typecheck && npm test -- --related. - Opened PR #210: migrate: Billing REST -> GraphQL. Status: tests passing, ready for review.
Review, merge, and clean up
Because packages are independent, you can review them in parallel. Merge dependency packages first, then run full CI after each merge to catch any unexpected interactions.
Once all PRs are merged, run a final cleanup pass: scan for remaining imports of src/lib/restClient.ts, delete REST-only utilities, and remove the old client file if nothing uses it.
Sharpen the migration playbook
When a run hits a file that does not fit the standard pattern, add the exception to the playbook or write it into memory (the notes a run recalls next time). After the first few packages, the migration becomes faster and more consistent.
Use the same playbook pattern for future migrations (new API clients, new service layers, or test-framework upgrades) by changing the import and call mappings.
The natural chain: when a migration touches many repos at once, use Fleet-Wide Maintenance Across Thousands of Repositories; when the change is a framework upgrade, use Create a React 18 to 19 Upgrade Playbook.