Skip to Content
Mesh
v1Migration from Mesh v0

Migration from GraphQL Mesh v0 (Experimental - Beta)

💡
This feature is still work-in-progress. Please report any issues you encounter.

This page is for people coming from Mesh v0 (.meshrc.yml, @graphql-mesh/cli, .mesh artifacts). Mesh v1 is a different product shape: Compose builds a Supergraph SDL, Hive Gateway serves it. The sections below keep the original v0 concepts and show what they became.

💡

Please make sure all of your @graphql-mesh/ packages are up-to-date on v0 first. Otherwise, the migration script may not parse your config as expected.

What changed (v0 vs v1)

If you are migrating from GraphQL Mesh v0, you should be aware of the following changes:

  • GraphQL Mesh no longer comes with a built-in gateway. You should setup Hive Gateway to serve the generated artifacts.
  • GraphQL Mesh no longer generates an executable JavaScript code in .mesh folder, but instead it builds a GraphQL SDL (Supergraph or Subgraph) that you can use with Hive Gateway.
  • GraphQL Mesh Transforms no longer have bare mode. There is only wrap mode now, and all the transforms are using Federation-compatible directives. Any transformed subgraph should be served using Hive Gateway.
  • If you deploy GraphQL Mesh v0 by using the http handler provided in the artifacts under .mesh, now you should take a look at Hive Gateway’s Deployment Guide to deploy your gateway.
  • GraphQL Mesh no longer runs GraphQL Code Generator internally, and it no longer writes SDKs into .mesh. You still have two typed paths: an operation SDK (getSdk + Hive Gateway) and an in-context SDK (context.Source.Query.field in resolvers). See Type-safe SDKs.
  • GraphQL Mesh no longer generates a Persisted Operations store. You should setup your gateway based on your needs. See here for more information.

GraphQL Mesh is now only responsible of generating a GraphQL SDL file supergraph.graphql or subgraph.graphql that you can use with Hive Gateway. It is not responsible for serving the generated artifacts.

Topicv0v1
Role of MeshOne runtime: load sources, merge, transform, and serve GraphQLCompose only: produce Supergraph/Subgraph SDL
ServingBuilt into @graphql-mesh/cli (mesh dev / mesh start)Hive Gateway (hive-gateway supergraph)
Config.meshrc.yml / .meshrc.yaml / .meshrc.json / .meshrc.jsmesh.config.ts (or .js) with composeConfig + gatewayConfig
Packages@graphql-mesh/cli + @graphql-mesh/<handler>@graphql-mesh/compose-cli + @omnigraph/* + @graphql-hive/gateway
Output.mesh/ (JS SDK, execute, HTTP handler, schema)supergraph.graphql (or .js) — SDL, not a Node server
Schema mergemerger (stitching / bare / federation)Federation-compatible composition
Transformsbare or wrap; can sit on a source or on the unified schemaWrap only; source-level in compose; Federation directives
Type mergingtypeMerging transform / stitchingFederation transform / @resolveTo
Operation SDKdocuments + sdkgetMeshSDK()Codegen + sdkRequester (typed-sdk example)
In-context SDK.mesh MeshContext / context.Source.Query.*@graphql-mesh/incontext-sdk-codegen
Persisted operationsMesh-generated storeHive Gateway persisted documents
In-process executegetBuiltMesh() / .mesh executeLocal Execution via Hive Gateway executor

Mental model: sources vs subgraphs

v0 called each upstream a source (handler + optional transforms), then merged them into a unified schema. v1 calls each upstream a subgraph. Compose loads it with a sourceHandler, applies transforms on that subgraph, then composes a supergraph.

v0v1
sources[].nameFirst argument of loadOpenAPISubgraph('Wiki', …) / loadGraphQLHTTPSubgraph('Countries', …)
sources[].handler.openapisourceHandler: loadOpenAPISubgraph(...)
sources[].transformssubgraphs[].transforms: [createPrefixTransform(...)]
Root transforms: (unified schema)Not supported — move onto a subgraph or use Federation
additionalTypeDefscomposeConfig.additionalTypeDefs (often with @resolveTo)
additionalResolversgatewayConfig.additionalResolvers (runtime, not compose)

Configuration Format

Before, Mesh used .meshrc.yml (or yaml/json/js). Now Mesh uses mesh.config.ts / mesh.config.js with two exports:

  • composeConfig — what Mesh Compose reads (mesh-compose)
  • gatewayConfig — what Hive Gateway reads (hive-gateway)

The same file can hold both so one project still has a single config, but the jobs are split.

Example: same gateway, two configs

v0 .meshrc.yml:

.meshrc.yml
sources: - name: Wiki handler: openapi: source: ./wiki.yaml transforms: - prefix: value: Wiki_ - name: Countries handler: graphql: endpoint: https://countries.trevorblades.com serve: port: 4000 cors: origin: '*' plugins: - responseCache: ttl: 1000

v1 mesh.config.ts (what the migrator aims to produce):

mesh.config.ts
import { createPrefixTransform, defineConfig as defineComposeConfig, loadGraphQLHTTPSubgraph } from '@graphql-mesh/compose-cli' import { defineConfig as defineGatewayConfig } from '@graphql-hive/gateway' import { loadOpenAPISubgraph } from '@omnigraph/openapi' export const composeConfig = defineComposeConfig({ subgraphs: [ { sourceHandler: loadOpenAPISubgraph('Wiki', { source: './wiki.yaml' }), transforms: [createPrefixTransform({ value: 'Wiki_' })] }, { sourceHandler: loadGraphQLHTTPSubgraph('Countries', { endpoint: 'https://countries.trevorblades.com' }) } ] }) export const gatewayConfig = defineGatewayConfig({ port: 4000, cors: { origin: '*' }, responseCaching: { ttl: 1000 } })

Run the migrator

Install @graphql-mesh/migrate-config-cli to generate mesh.config.ts from your v0 file.

npm install @graphql-mesh/migrate-config-cli

Then run the following command in your project directory:

npx mesh-migrate-config

Optional flags:

FlagMeaning
--dry-runPrint mesh.config.ts to stdout, do not write
--forceOverwrite an existing mesh.config.ts
[directory]Project root (default: cwd)

During the migration process, you might get some errors or warnings related to the deprecated or removed functionalities. Please make sure to update your legacy v0 configuration and setup according to those warnings and errors.

  • Errors mean the CLI did not write mesh.config.ts (root-level transforms, unknown handler, removed transform such as typeMerging).
  • Warnings mean it wrote a file, but you still have manual work (codegen, pubsub, merger, …).
💡

The config migrator is still experimental. Review mesh.config.ts and the messages it prints. Please report anything it gets wrong.

CLI and daily workflow

Goalv0v1
Dev server (rebuild schema from sources)mesh devmesh-compose -o supergraph.graphql then hive-gateway supergraph (re-compose when sources change)
Production schema artifactsmesh build.mesh/mesh-compose -o supergraph.graphql
Production HTTP servermesh start (loads .mesh)hive-gateway supergraph (loads SDL)
Validatemesh validateCompose + Gateway config / Hive schema checks
Serve a single sourcemesh serve-sourceCompose one subgraph, or point Hive Gateway at that subgraph SDL

v0 package.json often looked like "dev": "mesh dev", "build": "mesh build", "start": "mesh start". v1 splits that into compose (CI / build) and gateway (runtime).

Package Changes

Instead of @graphql-mesh/cli, you should now use @graphql-mesh/compose-cli and @graphql-hive/gateway.

npm uninstall @graphql-mesh/cli npm install @graphql-mesh/compose-cli @graphql-hive/gateway

Source handler packages moved from @graphql-mesh/<handler> to @omnigraph/* (GraphQL HTTP stays on compose-cli). The migrator prints the exact add/remove list for your config.

v0 handlerv0 packagev1 loaderv1 package
graphql@graphql-mesh/graphqlloadGraphQLHTTPSubgraph@graphql-mesh/compose-cli
openapi@graphql-mesh/openapiloadOpenAPISubgraph@omnigraph/openapi
jsonSchema@graphql-mesh/json-schemaloadJSONSchemaSubgraph@omnigraph/json-schema
grpc@graphql-mesh/grpcloadGRPCSubgraph@omnigraph/grpc
soap@graphql-mesh/soaploadSOAPSubgraph@omnigraph/soap
raml@graphql-mesh/ramlloadRAMLSubgraph@omnigraph/raml
mysql@graphql-mesh/mysqlloadMySQLSubgraph@omnigraph/mysql
postgraphile@graphql-mesh/postgraphileloadPostgreSQLSubgraph@omnigraph/postgresql
mongoose@graphql-mesh/mongooseloadMongooseSubgraph@omnigraph/mongoose
neo4j@graphql-mesh/neo4jloadNeo4jSubgraph@omnigraph/neo4j
odata@graphql-mesh/odataloadODataSubgraph@omnigraph/odata
thrift@graphql-mesh/thriftloadThriftSubgraph@omnigraph/thrift
tuql@graphql-mesh/tuqlloadSQLiteSubgraph@omnigraph/sqlite
supergraphconsume an existing supergraph as a Mesh sourceDo not compose. Give that SDL to Hive Gateway.@graphql-hive/gateway

GraphQL handler differences the migrator knows about:

  • v0 HTTP { endpoint } → v1 loadGraphQLHTTPSubgraph(name, { endpoint }) (copied as-is).
  • v0 code-first { source: './schema.ts' } → v1 { endpoint: './schema.ts' } (the v1 loader uses endpoint for URL or a local schema file).
  • v0 sources + fallback / race / highestValue is not auto-migrated. In v0 that was one handler with several HTTP backends. In v1, split them into subgraphs or keep a single endpoint.

See Source Handlers.

Transforms

v0 transforms could run in bare mode (mutate the schema in place) or wrap mode (schema wrapping). v1 only wraps, and emits Federation-compatible directives, so the result must be served by Hive Gateway (or another Federation-aware gateway). mode: wrap in YAML is dropped; it is implied.

v0 allowed root-level transforms: on the unified schema. v1 does not. Move them onto the relevant source, or replace stitching with Federation.

v0 transformv1What is different
prefixcreatePrefixTransformSame idea; docs
renamecreateRenameTransformdocs
filterSchemacreateFilterTransformDrop mode. A YAML list of globs becomes { filters: [...] }
encapsulatecreateEncapsulateTransformdocs
namingConventioncreateNamingConventionTransformdocs
hoistFieldcreateHoistFieldTransformv0 array → { mapping: [...] }
prunecreatePruneTransformdocs
federationcreateFederationTransformHow you declare keys / @merge in v1
extendcreateExtendTransform(typeDefs)typeDefs stay in compose; extend.resolversgatewayConfig.additionalResolvers
typeMergingmanualStitching-style merge → Federation / type merging
cachemanualWas a transform; now a gateway plugin — response caching
rateLimitmanualWas a transform; now gateway / @rateLimitrate limit
replaceFieldmanualUse hoist, rename, or additionalTypeDefs
resolversCompositionmanualadditionalResolvers or a gateway plugin

Serve, plugins, and runtime (compose vs gateway)

In v0, serve, plugins, cache, and customFetch lived next to sources in one YAML file. In v1, anything that builds SDL is compose; anything that runs requests is Hive Gateway.

v0v1
sources, source transforms, additionalTypeDefs, customFetch used while introspectingcomposeConfig (fetch on compose)
serve.*, plugins, cache, additionalResolvers, logger, runtime customFetchgatewayConfig (fetchAPI.fetch)
codegen, sdk, documentsGraphQL Codegen on the supergraph + Hive Gateway typed SDK (not Mesh CLI)
mergerNo replacement key; composition is Federation-style (migrator warns)
pubsubHive Gateway subscriptions — docs
persistedOperationsHive persisted documents
serve.extraParamNames, serve.browsernot migrated

serve field names

v0 servev1 gatewayConfig
portport
hostnamehost
endpoint (GraphQL path, default /graphql)graphqlEndpoint
playground: falsegraphiql: false
playgroundTitlegraphiql: { title }
corscors
healthCheckEndpointhealthCheckEndpoint
batchingLimitbatching: { limit }
sslCredentialssslCredentials
forkfork
staticFilesuseStaticFiles(...) plugin
browserskipped (dev-only auto-open)

Plugins

v0 pluginsv1
hivereporting: { type: 'hive', ... } and persistedDocuments when set
responseCacheresponseCaching
rateLimitrateLimiting
prometheusprometheus
maskedErrorsmaskedErrors
immediateIntrospectionuseImmediateIntrospection() in plugins
other Envelop / Yoga / Armor pluginsresolved when possible; otherwise add to gatewayConfig.plugins yourself

v0 cache: (Redis, Localforage, …) becomes gatewayConfig.cache: new Cache(...) with @graphql-mesh/cache-*. That is not the old Cache transform.

Type-safe SDKs

v0 mixed two things into .mesh. They are separate in v1.

Operation SDK (getSdk) — client-style

v0 documents + sdk + getMeshSDK(). v1: GraphQL Codegen typescript-generic-sdk + Hive Gateway sdkRequester. Canonical example: Hive Gateway examples/typed-sdk (CodeSandbox).

v0v1
documents: ['./src/**/*.graphql']Codegen documents (e.g. sdk/operations.graphql)
sdk: { generateOperations: { selectionSetDepth } }You own the .graphql operations
mesh build.mesh SDKgraphql-codegen against supergraph.graphql
import { getMeshSDK } from './.mesh'import { getSdk } from './sdk/generated'
getMeshSDK()getSdk(runtime.sdkRequester) or getSdk(getSdkRequesterForUnifiedGraph(...))

v0:

import { getMeshSDK } from './.mesh' const sdk = getMeshSDK() const { getSomething } = await sdk.myQuery({ someVar: 'foo' })

v1:

codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli' export default { schema: './supergraph.graphql', documents: 'sdk/operations.graphql', generates: { 'sdk/generated.ts': { plugins: ['typescript-operations', 'typescript-generic-sdk'] } } } satisfies CodegenConfig
import { readFileSync } from 'node:fs' import { createGatewayRuntime } from '@graphql-hive/gateway' import { getSdk } from './sdk/generated' await using runtime = createGatewayRuntime({ supergraph: readFileSync('./supergraph.graphql', 'utf-8') }) const sdk = getSdk(runtime.sdkRequester) const todos = await sdk.Todos()

See example.ts for mutations and subscriptions. In-process without createGatewayRuntime: getSdkRequesterForUnifiedGraph in Local Execution.

The migrator warns on sdk / codegen / documents and does not write codegen.ts.

In-context SDK (context.Source.Query.field) — resolvers

v0 mesh build also typed Mesh context so additionalResolvers could call a source without hand-writing GraphQL documents: context.Wiki.Query.someField({ root, args, context, info }).

v1: Codegen plugin @graphql-mesh/incontext-sdk-codegen against the supergraph. Example: e2e/openapi-javascript-wiki.

codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli' export default { schema: './supergraph.graphql', generates: { './types/incontext-sdk.ts': { plugins: ['@graphql-mesh/incontext-sdk-codegen'] } } } satisfies CodegenConfig
import type { MeshInContextSDK } from './types/incontext-sdk' async function viewsInPastMonth(root, { project }, context: MeshInContextSDK, info) { return context.Wiki.Query.metrics_pageviews_aggregate_by_project_by_access_by_agent_by_granularity_by_start_by_end( { root, args: { project /* … */ }, context, info, selectionSet: `{ items { views } }` } ) }

Full walkthrough: In-context SDK.

Using Artifacts

GraphQL Mesh no longer generates artifacts with execute or createBuiltMeshHTTPHandler. v0 deployment used those from .mesh after mesh build. v1 deployment uses an SDL file plus Hive Gateway.

v0 artifactv1
.mesh/index.js getBuiltMesh / executeCompose SDL + local execution (getExecutorForUnifiedGraph)
.mesh createBuiltMeshHTTPHandlerHive Gateway Node / serverless adapters — deployment
Generated SDK from sdk: / getMeshSDK()typed-sdk example (getSdk + sdkRequester)
MeshContext / context.Source.Query.*@graphql-mesh/incontext-sdk-codegen
Playground on mesh devGraphiQL on Hive Gateway

After a successful config migration:

  1. Install the packages the CLI printed and remove the old handler/CLI packages.
  2. Fix every error/warning (especially root transforms and type merging).
  3. Run npx mesh-compose -o supergraph.graphql to generate the supergraph schema.
  4. Run npx hive-gateway supergraph to start the gateway server.

Read more about Hive Gateway’s Deployment Guide to setup your gateway with the new artifacts.

If you need local execution or a typed SDK, see Local Execution & SDK and Type-safe SDKs. Operation SDK: examples/typed-sdk. In-context SDK: e2e/openapi-javascript-wiki. Compose background: Getting Started.

Last updated on