#Migrate to Hygraph
Migrating to Hygraph involves two distinct phases: rebuilding your schema, then importing your content. Hygraph gives you the Management SDK and Content API to handle both programmatically, as well as a UI-based option for schema creation.
This guide covers the full migration flow, from exploring your existing data to importing content, along with tips for specific field types such as assets, rich text, and relations.
#Prerequisites
- An active Hygraph project
- A Permanent Auth Token with Management API access (for schema creation via the SDK)
- A Permanent Auth Token with Content API mutations enabled (for content import)
- An export of your existing content in JSON or CSV format
#Step 1: Explore your current data
Before creating anything in Hygraph, examine the structure of your existing project and map it to Hygraph's data model.
Plan your schema
Work through the following questions:
- What models and fields do you currently have, and how do they map to Hygraph's field types?
- How do your models relate to each other?
- Are there structures you want to normalize or improve as part of the migration?
- Which data belongs in Hygraph, and which belongs elsewhere? For example, you may want image assets in Hygraph but video assets in a dedicated streaming service.
Export your existing content to JSON or CSV so you can inspect field names, content types, and relations.
The examples in this guide use the following CSV of authors:
oldId,firstName,lastName1,Stephen,King2,Frank,Herbert3,Brian,Herbert4,Kevin,Anderson5,Agatha,Christie6,Haruki,Murakami7,Isaac,Asimov
Hygraph supports over a dozen field types, from strings, booleans, and dates to polymorphic union types and remote field resolvers. You get a small set of system fields out of the box, but everything else is defined by you.
Some teams use migration as an opportunity to restructure their schema, for example, extracting repeated content into components. This can improve efficiency, but may require manual intervention when importing content. If you skip normalization for now, you can use String and JSON fields to represent most data without modification, though you will lose some filtering capability at the API level.
#Step 2: Create your schema
Create your schema
Create your schema before importing any content. You have two options: the Management SDK or the Hygraph UI. The SDK is faster for large or complex schemas and gives you a repeatable record of what was created.
#Use the Management SDK
The Management SDK lets you create models, fields, enumerations, components, and remote sources programmatically. All changes are submitted as a single transaction. If any operation fails, the entire batch rolls back automatically.
Install the SDK:
npm install @hygraph/management-sdk
Initialize the client:
const { Client } = require('@hygraph/management-sdk');// endpoint is your High Performance Content API URL// found in Project Settings > Endpoints > High Performance Content APIconst client = new Client({authToken,endpoint,name, // optional});
Use createModel to create a model:
client.createModel({apiId: '<your_api_id>',apiIdPlural: '<your_api_id_plural>',description: '<your_model_description>',displayName: '<Your model name>',});
To create two models, Author and Book:
client.createModel({apiId: 'Author',apiIdPlural: 'Authors',displayName: 'Author',});client.createModel({apiId: 'Book',apiIdPlural: 'Books',displayName: 'Book',});
Use createSimpleField to add fields to a model. The example below shows all available options. Use only the ones you need:
client.createSimpleField({apiId: '<your_api_id>',description: '<your_description>',displayName: '<your_display_name>',embeddableModels: '<embeddable_models>',embedsEnabled: '<boolean>',formConfig: '<form_config_json>',formExtension: '<form_extension>',formRenderer: '<form_renderer>',isHidden: '<boolean>',isList: '<boolean>',isLocalized: '<boolean>',isRequired: '<boolean>',isTitle: '<boolean>',isUnique: '<boolean>',migrationValue: '<migration_value>',parentApiId: '<parent_api_id>',position: '<int>',tableConfig: '<table_config_json>',tableExtension: '<table_extension>',tableRenderer: '<table_renderer>',type: SimpleFieldType.STRING,validations: '<SimpleFieldValidationsInput>',visibility: '<VisibilityTypes>',});
To add a required string field to the Author model:
client.createSimpleField({parentApiId: 'Author',type: SimpleFieldType.STRING,apiId: 'favoritePastime',displayName: 'Author Favorite Pastime',isRequired: true,visibility: VisibilityTypes.ReadWrite,});
Full migration example
The script below creates an Author model with firstName and lastName fields:
// migration.jsconst { Client, SimpleFieldType } = require('@hygraph/management-sdk');const client = new Client({authToken: '<your_permanent_auth_token>',endpoint: '<your_content_api_endpoint>',});// Create the Author modelclient.createModel({apiId: 'Author',apiIdPlural: 'Authors',displayName: 'Author',});// Add firstName field to Authorclient.createSimpleField({parentApiId: 'Author',apiId: 'firstName',displayName: 'First Name',type: SimpleFieldType.STRING,});// Add lastName field to Authorclient.createSimpleField({parentApiId: 'Author',apiId: 'lastName',displayName: 'Last Name',type: SimpleFieldType.STRING,});// Preview all changes before committingconst changes = client.dryRun();console.log(changes);
Run the script from the command line:
node migration.js
Review the changes array to confirm the operations that will be applied. Once you are satisfied, replace dryRun() with run() to commit the changes:
async function runMigration() {const result = await client.run(true);if (result.errors) {throw new Error(result.errors);}console.log(result.name);}runMigration();
Once the migration runs, verify the result by checking the schema editor in Hygraph or introspecting your endpoint.
If your schema includes components, enumerations, or remote source fields, create those at the schema level before adding them to models. See the Management SDK field creation examples for instructions.
Additional resources:
- Management SDK quickstart
- Management SDK methods reference
- Management SDK full example
- Batch migrations
#Use the UI
To create your schema in the Hygraph UI, navigate to the schema editor and create your models, then add fields to each one. The getting started guide covers creating models and adding fields.
#Step 3: Plan your content migration
With your schema in place, review your existing content and map it to the new structure before importing anything.
Order matters when content is relational. For example, you must create asset entries before creating content entries that reference them, otherwise the relation cannot be established at import time.
As you plan, identify:
- Which content needs to be migrated first to unblock dependent content
- Which content is critical vs. supporting, so you can prioritize accordingly
- Where the shape of your existing data differs from your new input types, and what transformation is needed
#Step 4: Import your content
Import assets before content entries. Relations cannot be established until the assets they reference exist. How you upload assets depends on which asset system your project uses.
API Endpoints
#Assets
Projects created after February 2024 use the Hygraph Asset Management system. Projects older than that use the Legacy asset system. The upload process differs between the two:
- Hygraph Asset Management: Asset uploads are part of the native GraphQL API. Upload through
createAssetmutations instead. - Legacy asset system: Uses a dedicated HTTP upload endpoint at
/uploadappended to your project URL.
To check which system your project uses, navigate to Project Settings > Access > Endpoints and look for an asset upload endpoint. If one is listed, your project uses the legacy system. If not, it uses Hygraph Asset Management.
You will need a Permanent Auth Token with Mutations access enabled to upload assets.
File size limits depend on your plan. Check the pricing page for details.
Assets follow the same environment and authorization settings as all other content in your project.
After uploading, publish your assets before they can be served alongside published content. For full asset upload documentation, see Uploading assets.
Upload by file — Hygraph Asset Management
First, create the asset via mutation to receive the upload URL and credentials:
Then upload the file using the credentials from the response:
curl --request POST \--url $URL \--form X-Amz-Date=$DATE \--form key=$KEY \--form X-Amz-Signature=$SIGNATURE \--form X-Amz-Algorithm=$ALGORITHM \--form policy=$POLICY \--form X-Amz-Credential=$CREDENTIAL \--form X-Amz-Security-Token=$SECURITY_TOKEN \--form file=@./test.jpg
Upload by remote URL — Hygraph Asset Management
mutation uploadByUrl {createAsset(data: {uploadUrl: "https://images.unsplash.com/photo-1682687218147-9806132dc697"}) {idurl}}
Upload by file — legacy asset system
Upload by remote URL — legacy asset system
#Content entries
To find your Content API endpoint, go to Project Settings > Access > Endpoints > High Performance Content API.
Use GraphQL mutations to create content entries. Hygraph auto-generates mutations for every model you create. Because existing data rarely maps 1:1 to your new schema, you will likely need to transform your dataset to match your new input types before importing.
The script below shows a complete import example using the CSV authors file from Step 1:
// Import necessary librariesconst { GraphQLClient, gql } = require('graphql-request');const csvToJson = require('csvtojson');require('dotenv').config();// Initialize GraphQL clientconst client = new GraphQLClient(process.env.HYGRAPH_ENDPOINT, {headers: {authorization: `Bearer ${process.env.HYGRAPH_TOKEN}`,},});// Build a mutation from a data rowfunction createMutation(data) {return gql`mutation MyMutation {createAuthor(data: {firstName: "${data.firstName}",lastName: "${data.lastName}",oldId: "${data.oldId}"}) {id}}`;}// Run the migrationasync function run() {// Load and parse the CSVconst data = await csvToJson().fromFile('./data.csv');// Build mutations from each rowconst mutations = data.map((item) => createMutation(item));// Execute each mutation with a 1-second delay between requestsmutations.forEach((mutation, index) => {setTimeout(() => {console.log(`Running mutation ${index + 1} of ${mutations.length}`);client.request(mutation).then((response) => {console.log(response);});}, (index + 1) * 1000);});}run();
See rate limits for guidance on request frequency.
#Rich text
Hygraph stores rich text as an Abstract Syntax Tree (AST) based on Slate. If your existing content stores rich text as HTML or another format, you need to convert it before importing.
- Convert: Use Hygraph's HTML-to-Slate AST converter to transform your existing rich text into the correct AST format.
- Import: Use a
createmutation with aRichTextASTvariable to import the converted content.
For additional rich text utilities, see the Hygraph rich text helpers.
#Relations
There are two approaches to migrating relational content.
Option 1: Create with nested mutations
Use a create mutation with a nested create to build both sides of a relation in one request. For subsequent entries that share the same related record, use a connect mutation instead of creating a duplicate.
Option 2: Create separately, then connect
Create all entries for each model first using create mutations, then wire them together using update mutations or update many mutations. This approach is more straightforward but requires more total mutations.
Option 2 requires more mutations to be sent. Review the rate limits documentation before choosing your approach.
#Migration best practices
Follow these guidelines to keep your migration predictable and recoverable:
- Plan the full migration before you start. Map your existing schema to Hygraph models and fields, and identify any transformations needed.
- Use the migration as an opportunity to improve your schema. Hygraph features like components can reduce duplication. Restructure where it makes sense.
- Migrate in dependency order. Assets must exist before content entries that reference them. Shared models must exist before models that connect to them.
- Prioritize critical content. Identify your most important content and migrate it first, before supporting or supplementary content.
- Avoid large, complex mutations. If a model connects to many other models, do not try to create and connect everything in a single mutation. Space requests out and stay within rate limits.
#What's next
- Management SDK: Full reference for creating and updating schema elements programmatically.
- Content API mutations: Reference for create, update, connect, and nested mutations.
- Upload assets: Full documentation for asset uploads, including both legacy and current asset systems.
- Rate limits: Understand request limits before running large-scale imports.
- Field types: Reference for all field types available in Hygraph.