rgql: An AST‑Driven, Type‑Safe Tool for Deterministic GraphQL Refactoring
rgql is an AST-driven, type-safe GraphQL refactoring tool that renames types, fields and fragments across schemas and embedded TypeScript queries reliably.
GraphQL refactoring often looks simple on paper — change a type or field name and move on — but in practice it’s a brittle, file-by-file chore that can silently break clients. rgql tackles this problem by operating on parsed GraphQL and TypeScript ASTs, using schema-aware type resolution to make renames deterministic and safe across .graphql schema files and graphql/gql tagged template literals inside .ts/.tsx code. The result is a CLI utility that does what ad‑hoc find-and-replace cannot: apply semantic, provably correct renames while offering the guards and feedback teams (and automated agents) need to avoid introducing schema drift.
Why GraphQL renames break naive find-and-replace
Renaming a field is deceptively tricky. Field names are reused across types, queries, and nested selections; the same literal token can represent different underlying schema fields depending on context. A text or regex substitution will happily change every matching identifier, turning an innocuous change into a broken client. Even editor tooling that matches against strings can’t reliably know whether the token under the cursor is part of a schema definition, a query selection, or a nested object of another type.
Additionally, GraphQL codebases commonly mix standalone .graphql files and embedded queries inside TypeScript template literals. Positions for those embedded queries are relative to the string literal, not the file; precise edits require translating those offsets to absolute file locations. Large monorepos and projects that implement interfaces further complicate renames: changing a field declared on an interface can imply changes across multiple implementing types.
How rgql uses ASTs and schema type information to rename correctly
rgql avoids surface-level text surgery by parsing the entire schema and building a complete type graph using graphql-js primitives. When the tool analyzes operations and fragments it walks their ASTs with type-aware visitors so each field node is examined in the context of its resolved parent type. That means a field named firstName is only renamed when the visitor can prove its parent type is the one you intend — e.g., User.firstName becomes User.fullName — while Product.firstName remains untouched.
This approach relies on two core ideas: (1) parse and resolve, not guess; and (2) make renames deterministic. The rename pipeline computes a plan — a RenameOutcome — that describes every change without touching files, which the CLI may later apply. This separation ensures previews and dry runs are faithful and that the write step is purely about applying a validated plan.
What a rename workflow looks like with rgql
From a user perspective, rgql exposes a simple command surface. Common operations include renaming types, fields, and fragments. Workflows typically start with a dry run that prints the planned edits, for example:
rgql rename field User.firstName User.fullName
This shows a concise list of files and locations that would change; adding –write applies the modifications. There are flags for interactive confirmation (-i), forcing cross-type/interface cascades (–force), and project-specific configuration (–config, –project). That combination of preview, interactivity, and guarded force operations maps well to both human workflows and automated pipelines.
Why rgql is useful for AI coding agents
AI coding assistants and programmatic agents face two persistent problems when modifying code: limited context windows and brittle text transformations. When told to rename a GraphQL field, an agent must locate the schema entry, search every document and embedded query, and reason about type context for each occurrence — tasks that rapidly consume tokens and risk omissions.
rgql turns a complex multi-file reasoning task into a single, verifiable command. An agent can invoke rgql with the intended rename and either run a dry run to inspect the calculated RenameOutcome or execute the write. Because the tool itself performs AST-based resolution, the agent does not need to parse or read all files, reducing token usage and failure modes. That makes rgql a practical primitive for automation frameworks and agent-driven developer tools that require safe, atomic refactorings.
Interface awareness and breaking-change protection
When a rename would affect an interface or shared contract, rgql surfaces the impact and demands an explicit decision. If a field is defined on an interface, the tool lists all implementing types that would be affected and refuses to perform a partial rename unless the user opts in. This behavior prevents silent schema breakage: without –force the operation aborts or requires interactive agreement to rename all related fields consistently.
These checks are more than convenience — they are necessary correctness guarantees. In GraphQL, changing a field on an interface without updating all implementations or clients can produce runtime errors and subtle client-side bugs. rgql’s interactive prompts and abort-on-risk defaults help teams and agents avoid those outcomes.
Architecture: pure core, impure shell for testability and predictability
rgql is organized around a clear IO boundary. Core rename logic is implemented as pure functions: given a RenameCommand, a schema, and a set of documents, the pipeline returns a RenameOutcome. All validation, rename plan computation, and AST transformations are deterministic and side-effect free. The shell layer — the CLI, filesystem adapters, and user interaction — is responsible solely for IO and presentation.
This separation yields multiple benefits. The pure core is trivial to unit test and to reason about; it can be run in memory or in isolation by automated agents. The shell can pattern-match on RenameOutcome variants (dry-run, written, no-changes, validation-error, interface-skipped, etc.) and perform the appropriate file writes or prompt sequences. Keeping the decision logic pure also makes it easier to integrate rgql into CI pipelines, code-mod bots, and agent workflows where deterministic behavior is critical.
TypeScript design choices: branded types and Result types
To catch class-of-errors at compile time, rgql uses branded types for domain values such as TypeName and FieldName. Instead of treating both as plain strings — which invites accidental swapping — branded types encode a compile-time distinction while imposing zero runtime overhead. That pattern reduces developer errors inside the codebase and produces clearer APIs when invoking rename commands programmatically.
Error handling favors an explicit Result type over exceptions. Functions return a discriminated Result that is either ok with a value or an error carrying structured information. This aligns with functional error composition — mapResult and flatMapResult — making error paths explicit and easier to compose into larger flows without hidden control flow or unexpected thrown exceptions.
Detecting and rewriting embedded GraphQL queries inside TypeScript
A major value proposition for rgql is handling embedded queries. Many projects place GraphQL inside tagged template literals (graphql... or gql...) in .ts/.tsx files. rgql leverages ts-morph and the TypeScript AST to locate those tagged templates, extract their GraphQL source, parse it into an AST, and compute the precise edits required. Because GraphQL AST node positions are relative to the template string, rgql translates those offsets into absolute file positions for precise replacement.
This capability eliminates a frequent refactor gap where schema tools only touch .graphql files and editors treat embedded operations as opaque strings. By bridging the schema and code, rgql ensures renames are fully applied across the codebase, including components, hooks, and generated artifacts that embed queries.
Developer experience: commands, flags, and configuration
rgql integrates with standard GraphQL project configuration via graphql-config, so it can discover schema and document globs in typical layouts. Installation currently targets Bun for building a single distributable binary, though npm/Homebrew distribution is on the roadmap.
Core commands include:
- rgql rename type User Account — change a type name across schema & documents
- rgql rename field User.firstName User.fullName — rename a field with type-aware checks
- rgql rename fragment UserBasic UserSummary — rename a fragment symbol
Key flags:
- –write to apply edits (default behavior is a dry run)
- -i for interactive confirmation per change
- –force to allow interface cascade renames (use with caution)
- –config and –project for multi-project or custom configurations
Dry-run output is intentionally concise and actionable: file paths, locations, and the before→after tokens. That information is useful for both humans reviewing changes and for tools that might parse rgql output to perform additional steps.
Integration points and related tooling
rgql sits at an intersection of several ecosystems. It builds on graphql-js for schema resolution, ts-morph for TypeScript AST analysis, and common CLI frameworks for UX. Its design philosophy resembles language server rename primitives (gopls, TypeScript language server) and AST-based code-mods (ts-morph, jscodeshift), but specialized for GraphQL’s typing semantics.
Because rgql produces deterministic, validated outcomes, it can integrate into:
- CI pipelines that enforce safe refactors
- Code-mod bots that apply bulk renames across monorepos
- AI agent toolchains that prefer atomic, auditable operations over ad-hoc text edits
- Developer tooling dashboards or IDE integrations that preview semantic changes
Referencing adjacent technology stacks — schema generators, codegen tools, GraphQL client libraries, and type-safety tooling — helps teams reason about where to place rgql in their workflow.
Practical limitations, gotchas, and edge cases
No tool is a universal fix. rgql’s approach relies on accurate schema inputs and correct graphql-config discovery; projects with nonstandard schemas or dynamically generated operations may need explicit configuration. Embedded queries that aren’t tagged (for example, commented markers like / GraphQL /) are a known gap on the roadmap. Projects that interact with compiled artifacts or rely on string concatenation for queries will require special handling.
When a rename touches generated files or downstream consumers (mobile apps, other services), teams should coordinate versioning and deploy strategies. rgql will tell you what to change in source files it scans, but it cannot update external services that rely on your API — treating refactors as schema migrations is still the team’s responsibility.
Broader implications for developer workflows and the software industry
Tools like rgql reflect a broader trend toward semantics-aware developer tooling. As teams adopt typed APIs and stricter schema contracts, the surface area for safe, automated refactors grows. Deterministic, AST-driven tools can reduce the cognitive load on engineers and shrink the window for human error during cross-cutting changes.
For organizations building AI-driven developer workflows, rgql represents a crucial pattern: provide agents with well-scoped, verifiable primitives that encapsulate domain knowledge. Instead of delegating high-risk, context-heavy refactors to language models, teams can expose a small set of guarded operations that agents can call reliably. That reduces the need for expensive context transfer and makes automation safer.
On the developer tooling market, the emphasis is shifting from best-effort text manipulation to operations that are provably correct with respect to program semantics. That shift favors libraries and utilities that can compose type information, AST transformations, and explicit outcome models. In turn, it encourages tighter integrations between schema management, code generation, and CI-driven governance.
Getting started and where to experiment
To try rgql, set up a minimal graphql-config that points at your schema files and document globs. Build the tool (current instructions use Bun to produce a single binary), run a dry run to preview planned edits, and iterate interactively until you’re confident. Because rgql’s core is pure and produces rich RenameOutcome variants, it’s straightforward to script and include as a step in automation or CI.
For teams interested in automation, start by running rgql in dry-run mode inside CI to collect potential renames or validate that a proposed schema change won’t break client operations. For AI-assisted development, expose rgql as a callable action for agents so they can perform renames without consuming repository context.
Roadmap: features coming next
Planned enhancements include support for query detection patterns that aren’t strictly tagged (comment-marked queries), a command to rename enum values, a watch mode to apply continuous refactorings during active development, and broader distribution channels like npm and Homebrew. Each of these aims to reduce integration friction and expand the set of projects that can adopt rgql safely.
rgql’s development choices — a pure core for reasoning, an impure shell for IO, and explicit safety checks — make it a solid candidate for incremental feature additions without compromising correctness.
As GraphQL ecosystems mature, tools that make schema evolution safer and more auditable are likely to become essential. Continued investment in robust AST tooling, improved detection for embedded operations, and tighter integrations with code generation and CI systems will determine how teams manage large-scale API changes. The next wave of developer tooling will increasingly favor small, verifiable primitives that agents and humans can trust to perform high-impact edits with minimal risk.
















