# Hygraph documentation — Get Started Source: https://hygraph.com/docs/getting-started See https://hygraph.com/llms.txt for the curated index. --- # Access and permissions Source: https://hygraph.com/docs/getting-started/access-and-permissions/access-and-permissions-overview Every user and API client in Hygraph is assigned a set of permissions that controls what they can read, write, and configure. This section covers how to set that up, whether you are onboarding a team member, creating a custom role, or securing API calls. Hygraph uses three mechanisms to grant permissions: - **Roles** control what authenticated users can do in the project. - **Permanent Auth Tokens (PATs)** control what API clients can do. - **Public Content API** settings control what unauthenticated requests can read. All three use the same permission types: content permissions (read, create, update, delete, publish, unpublish) and Management API permissions (schema, environments, settings). Content permissions are environment-specific. Management API permissions apply across all environments in the project. When setting up access for your project, work through these decisions in order: 1. **Who needs access?** Identify everyone who needs access to your project. For each person or system, determine whether they should be granted access through a role, a PAT, or the public Content API settings. 2. **What can they do?** Define content permissions (which models, locales, and content stages) and any Management API permissions relevant to their role or token. 3. **On which environments?** Content permissions are environment-specific, so you configure them separately per environment. Management API permissions apply globally across all environments in the project. ## Who is this section for? - Project admins managing users and environments - Developers securing API access for applications ### Manage your team - [Manage team members](/docs/getting-started/access-and-permissions/manage-team-members): Invite collaborators to your project, assign roles, and manage access as your team grows. - [Roles](/docs/getting-started/access-and-permissions/user-roles-and-permissions): Understand system roles, create custom roles, and define what users can read, write, publish, or manage. ### Configure access - [API access](/docs/getting-started/access-and-permissions/api-access): Configure public Content API access, create Permanent Auth Tokens (PATs), and authenticate API requests. - [Content permissions](/docs/getting-started/access-and-permissions/content-api-permissions): Reference for content permission rules, including model-level, locale, and content stage configuration. - [Management API permissions](/docs/getting-started/access-and-permissions/management-api-permissions): Reference for permissions that control UI visibility for roles and programmatic access for PATs across schema, environments, and project settings. - [Permission combinations by job](/docs/getting-started/access-and-permissions/permission-combinations-by-job): Combined permission sets for jobs such as publishing or using schema. --- # API access Source: https://hygraph.com/docs/getting-started/access-and-permissions/api-access The **API Access** section of your project settings is where you find your API endpoints, configure unauthenticated content permissions, and manage Permanent Auth Tokens (PATs). Navigate to **Project Settings > Access** to get started. For a conceptual overview of authorization and authentication in Hygraph, see [Authorization](/docs/api-reference/basics/authorization). ## Endpoints The **Endpoints** section lists the API URLs for your project's environments. Click (Copy icon) next to any URL to copy it to your clipboard. | Endpoint | Description | |-------------------------------------|---------------------------------------------------------| | High Performance Content API | Low latency, high read throughput endpoint for content delivery and asset uploads. | | Management API | Handles all structural elements of a project. Use it via the [Management SDK](/docs/api-reference/management-sdk/management-sdk). | | MCP Server API | | ![Endpoints](/images/docs/user-guides/api-access/api-access-publicapi.png) ## Unauthenticated requests: Content API The **Content API** section lets you configure access permissions for unauthenticated requests to your project's Content API. To open this section, navigate to **Project Settings > Access > Content API**. ### Default stage for public content delivery This setting determines which content stage is served when no stage parameter is included in a query or HTTP header. To change it: 1. Click **Change default stage** next to the current stage tag. 2. Select a stage from the available options. 3. Click **Change** to save. [Learn more about the default public stage](/docs/api-reference/basics/authorization#default-public-stage). ### Content permissions Content permissions determine what unauthenticated users can read from your Content API. This section lets you view, add, edit, and delete permissions. Because requests to Content API are not authenticated, we do not recommend enabling permissions to mutate content here. Use [Permanent Auth Tokens](#authenticated-requests-permanent-auth-tokens) if you intend to create, update or delete your content via the API. ![API Access - Content permissions](/images/docs/user-guides/api-access/content-permissions.png) If there are no content permissions yet, the empty state offers **Add permissions** and **Initialize defaults**. **Initialize defaults** grants **Read** on all models for all locales, scoped to the default public content delivery stage. For a full explanation of how content permissions work, including locales, stages, and conditions, see [Content permissions](/docs/getting-started/access-and-permissions/content-api-permissions).
Add a permission
1. Go to **Project Settings > Access > Content API**. 2. Click **Add permissions**. If there are no content permissions yet, the empty state offers **Add permissions** and **Initialize defaults**. **Initialize defaults** grants **Read** on all models for all locales, scoped to the default public content delivery stage. - Use the **Model** dropdown to select the model to apply permissions to. Select **All** to apply them across all models. - Use the checkboxes to select the actions to grant. Some actions reveal additional options for **Locales** and **Stages**. 5. Click **Create** to save.
Edit a permission
**Edit** is available only when the permission has locale or stage settings. Click the context menu in a permission row and select **Edit**. A dialog will appear where you can update the locale or stage. ![API Access - Edit permissions](/images/docs/user-guides/api-access/edit-permissions.png)
Delete a permission
Click the context menu in a permission row and select **Delete**. Confirm the deletion in the dialog that appears. This action is permanent and cannot be undone. ![API Access - Delete permissions](/images/docs/user-guides/api-access/delete-permissions.png)
## Authenticated requests: Permanent Auth Tokens Permanent Auth Tokens (PATs) provide authenticated access to the Content API and Management API using Bearer token authentication. Each token can be configured with its own set of content and Management API permissions. To open this section, navigate to **Project Settings > Access > Permanent Auth Tokens**. The tokens table lists all existing tokens for the project, including name, created date, token, and JWT ID. See [Authorization - Permanent Auth Tokens](/docs/api-reference/basics/authorization#permanent-auth-tokens) for a conceptual overview of how PATs work. ![API Access - Permanent Auth Tokens](/images/docs/user-guides/api-access/api-access-pat.png) ### Add a Permanent Auth Token (PAT) 1. Click **Add token**. - To create a token preconfigured for Hygraph's MCP server, click **Generate MCP PAT** instead. See [Set up the MCP server](/docs/hygraph-ai/mcp-server-setup). 2. Enter a name and optional description for the token. 3. Select a default stage for content delivery using the radio buttons. 4. Click **Add & configure permissions** to create the token. The token details screen opens, where you configure content and Management API permissions. **Add token** does not enable any content or Management API permissions. It only sets the token's default content delivery stage. Until you add permissions, the token cannot read content or call the Management API. ### Copy a token You can copy the token value from the tokens table or from the token detail view. Treat the token like a secret: anyone with it can use the permissions granted on that token. From the tokens table: 1. Go to **Project Settings > Access > Permanent Auth Tokens**. 2. In the **Token** column, click (Copy icon). From the token detail view: 1. Click the token row, or select **Edit** from its context menu. 2. In the **Token** field, click (Copy icon). ### Configure content permissions Until you add content permissions, the token cannot read content.
Change the default content delivery stage
From the token detail view you can change the default content delivery stage by clicking **Change default stage**. This setting determines which content stage is served when no stage parameter is included in a query or HTTP header. To change it: 1. Click **Change default stage** next to the current stage tag. 2. Select a stage from the available options. 3. Click **Change** to save.
Add content permissions
To add content permissions on a PAT: 1. Go to **Project Settings > Access > Permanent Auth Tokens**. 2. Click the token row, or select **Edit** from its context menu. 3. Under **Content API**, click **Add permissions**. If the token has no content permissions yet, the empty state offers **Add permissions** and **Initialize defaults**. **Initialize defaults** grants **Read** on all models for all locales, scoped to the token's default stage. - Use the **Model** dropdown to select the model to apply permissions to. Select **All** to apply them across all models. - Use the checkboxes to select the actions to grant. Some actions reveal additional options for **Locales** and **Stages**. 4. Click **Create** to save.
For what each action means, see [Content permissions](/docs/getting-started/access-and-permissions/content-api-permissions#permission-actions). ### Configure Management API permissions Until you enable Management API permissions, the token cannot call the Management API. A new token does not have any permissions enabled, by default To configure Management API permissions for a token: 1. Go to **Project Settings > Access > Permanent Auth Tokens**. 2. Click the token row, or select **Edit** from its context menu. 3. Under **Management API**, the table lists all available permissions. Enabled permissions are toggled on. You can perform the following actions: - Use **Group by Domain** or **Group by Action** to group the list. - Filter the list with **All permissions**, **Enabled permissions**, or **Disabled permissions**. - Use the toggles to enable or disable individual permissions. - Use the checkboxes to select multiple permissions, and then enable or disable them in bulk. Some Management API permissions are **UI-only** and have no effect on a PAT. For a full reference of all available permissions, see [Management API permissions](/docs/getting-started/access-and-permissions/management-api-permissions). ### Edit a token Click a token row in the table, or select **Edit** from its context menu. The token detail view will open, where you can modify token name, copy the token string, and update [content permissions](#configure-content-permissions) and [Management API permissions](#configure-management-api-permissions). ![API Access - Edit token](/images/docs/user-guides/api-access/edit-token.png) ### Delete a token Select **Delete** from the token's context menu, or click **Delete** from within the token detail view. Confirm the deletion in the dialog that appears. Deleting a token is permanent and invalidates all JWTs (JSON Web Tokens) associated with it. ![API Access - Delete token](/images/docs/user-guides/api-access/delete-token.png) ### Can’t find your token in Hygraph? If you copied a PAT a while ago and can’t find the same token string in Hygraph today, the token may still be active even if it looks different. Hygraph uses JWTs (JSON Web Tokens) for Permanent Auth Tokens (PATs). In cases such as audience updates or issuer migrations, the encoded JWT string may change while still representing the same underlying token. Even after such changes, the token remains valid as long as the `jti` (JWT ID) claim within the token's payload remains unchanged. The `jti` claim serves as the authoritative identifier for the token. To verify whether two tokens refer to the same underlying token, follow these steps: 1. Go to https://jwt.io and paste the token that you want to check. This token is no longer visible in Hygraph Studio. 2. Decode the token and locate the `jti` claim in the payload. 3. In Hygraph Studio, go to **Project settings > Access > Permanent Auth Tokens** and check the `jti` values for the tokens listed there. 4. Compare the `jti` values. If the `jti` value found in Step 2 matches the `jti` of a token available in Hygraph Studio, it is the same underlying Permanent Auth Token, even if the encoded JWT differs. The token is still active and has not been revoked. You can then decide whether to keep it or revoke it. - If you want to keep the token, you can replace the deleted JWT with the one that matches from Hygraph Studio. - If you want to revoke the token, you can delete it from Hygraph Studio. This action invalidates all JWTs associated with that token, including any previously issued ones. ![Permanent Auth Tokens list](/images/docs/user-guides/api-access/api-access-tokens.png) ## What's next - [Content permissions](/docs/getting-started/access-and-permissions/content-api-permissions): How content permissions work and their limits. - [Management API permissions](/docs/getting-started/access-and-permissions/management-api-permissions): How Management API permissions work and their limits. - [Roles and permissions](/docs/getting-started/access-and-permissions/user-roles-and-permissions): Create and configure roles, assign permissions, and set up role-based access. - [Authorization](/docs/api-reference/basics/authorization): Public API permissions, PATs, and endpoints. --- # Content permissions Source: https://hygraph.com/docs/getting-started/access-and-permissions/content-api-permissions Content permissions control who can read, create, update, delete, publish, and unpublish content in your Hygraph project. You can configure permissions for unauthenticated requests to the Content API, individual Permanent Auth Tokens (PATs), and custom roles. Content permissions are environment-specific. If you are working with multiple environments, you must configure permissions separately for each one. You can configure up to 50 content permissions in a project [environment](/docs/api-reference/basics/environments). You can distribute these across the unauthenticated Content API, PATs, and custom roles as needed. ## Permission actions The permission system is built on seven action types. Granting an action gives unauthenticated requests, a PAT, or a custom role permissions to perform that action on all models or a specific model. | Action | Description | Required permissions | |-----------------|-------------------------------------------|----------------------------------------------------------------------------| | `Read` | Read content entries. | — | | `Read versions` | View version history for content entries. | — | | `Create` | Create new content entries. | `Read` on Draft stage and default locale, and `Create` | | `Update` | Modify existing content entries. | `Read` on Draft stage, and `Update` | | `Delete` | Delete content entries. | `Read` on all stages, `Delete`, and `Unpublish` on all stages except Draft | | `Publish` | Publish content entries. | `Read` on Draft stage, and `Publish` on Draft and target stage | | `Unpublish` | Unpublish content entries. | `Read` on all stages, and `Unpublish` on source stage |
For custom roles
Custom roles have no content permissions by default. At a minimum, a custom role that uses the content editor need the following permissions: - **Read** access on the `User` system model. This is important for custom roles that interact with the UI, as user attribution fields (`createdBy`, `updatedBy`, and `publishedBy`) will not display without these permissions. Missing these permissions can also cause `not allowed` errors when mutating content from the content editor. See [System fields: User fields](/docs/api-reference/schema/system-fields#user-fields) for more information. - **Read versions**. This is required for versioning to display correctly in the content editor.
## Set up unauthenticated access to the Content API Unauthenticated requests to the Content API are intended for reads. To expose published content publicly: 1. Navigate to **Project Settings > Access > Content API**. 2. In the **Content Permissions** box, click **Initialize defaults**. This sets `Read` permissions on all models for the default public content delivery stage, which is **PUBLISHED** unless you changed it. 3. If you need custom rules instead, click **Add permissions**, select **All models**, check **Read**, leave **Locales** and **Stages** at their defaults, and click **Create**. The Content API now serves that content to unauthenticated requests. For the add, edit, and delete steps on this screen, see [Unauthenticated requests: Content API](/docs/getting-started/access-and-permissions/api-access#content-permissions). For what each action means, see [Permission actions](#permission-actions). ![Content API read permissions for unauthenticated requests](/images/docs/api-reference/basics/public-api-read.png) [Learn more about authorization](/docs/api-reference/basics/authorization). ## Set up a PAT with model-specific permissions A [Permanent Auth Token (PAT)](/docs/api-reference/basics/authorization#permanent-auth-tokens) can be scoped to specific models and actions. The example below configures a PAT that can read, create, and update entries in a `Post` model only. 1. Navigate to **Project Settings > Access > Permanent Auth Tokens** and click **Add token**. 2. Enter a token name and optional description, then click **Add & configure permissions**. 3. Under **Content API** in the token detail view, click **Add permissions**. 4. Select the **Post** model and check **Read**, **Create**, and **Update**. Leave **Locales**, **Stages**, and **Condition** at their defaults, then click **Create**. The token can now read, create, and update `Post` entries. With this configuration, the token cannot access related models such as `Author`, `Asset`, or `SEO`. To connect posts to those models, add separate permissions for each. For the general add permission steps on a PAT, see [Authenticated requests: Permanent Auth Tokens](/docs/getting-started/access-and-permissions/api-access#configure-content-permissions). For what each action means, see [Permission actions](#permission-actions). ## Scope content permissions The examples below show how to scope a content permission in the UI. They apply when you add a permission on a custom role, a Permanent Auth Token, or the unauthenticated Content API. For combined permission sets for a job, such as a read-only reviewer or a publisher, see [Permission combinations by job](/docs/getting-started/access-and-permissions/permission-combinations-by-job). ### By model Select the target model from the **Model** dropdown when creating a content permission. Permissions will apply only to entries of that model. ![Setup by models](/images/docs/user-guides/roles-and-permissions/setup-example-models.png) Selecting multiple models at once is not supported, unless you select all models. To configure the same permissions on two different models, create a separate permission for each. When permissions are set on a model that has [relations](/docs/api-reference/schema/field-types#reference), permissions may be required on both models. For example, in a schema with `Post` and `Author` models, updating a `Post` to connect it to an `Author` also requires update permissions on the `Author` model, since an author can reference many posts. ### By locale When selecting a permission action, use the **Locales** dropdown to restrict it to one or more specific locales. To create or update a document with non-localized fields, the user or token must have access to the default locale. If no default locale is set, the user or token must have access to all locales. ![Setup by locales](/images/docs/user-guides/roles-and-permissions/setup-example-locales.png) You must also grant access to the default locale for any role that needs to create or update content. ### By content stage Use the **From stages** and **To stages** dropdowns to restrict publish and unpublish actions to specific stages. For example, you can limit a role to publishing from **Draft** to a **QA** stage only, preventing direct publishing to **Published**. ![Setup by content stage](/images/docs/user-guides/roles-and-permissions/setup-example-content-stage.png) Check out [Content Workflows](/docs/developer-guides/project/content-workflows) to learn how to use content stages for approval workflows. For help with a specific setup, contact the Hygraph support team. ### By environment Management API permissions apply to all environments in a project. Content permissions are environment-specific, so you can configure different permissions on each environment for the same role. For example, to give a role read-only access on the master environment and publish access on a secondary environment: 1. Switch to your master environment. 2. Set up the role as read-only, as described in [Content reviewer](/docs/getting-started/access-and-permissions/permission-combinations-by-job#content-reviewer). 3. Switch to the secondary environment. [Learn how to switch environments](/docs/developer-guides/project/manage-project-environments#switch-environments). 4. Open the custom role and select **View permissions**. 5. Add the **Publish** and **Unpublish** content permissions. 6. Enable the additional Management API permissions required for publishing, as described in [Publisher](/docs/getting-started/access-and-permissions/permission-combinations-by-job#content-publisher). ![Setup by environment](/images/docs/user-guides/roles-and-permissions/setup-example-content-stage.png) ## Use conditions Conditions let you restrict a permission to specific content entries. Instead of granting a role, token, or the public Content API access to all entries in a model, you can scope it further using a GraphQL `where` clause. For example, for entries with a particular field value, tag, or ID. Conditions require familiarity with GraphQL `where` clauses. Use the API Playground to build and test a condition before applying it to a role. To add a condition when configuring a permission: 1. Open the custom role, Permanent Auth Token, or public Content API permissions screen, and click **Add permissions**. 2. Select the target model from the **Model** dropdown. 3. Check the actions you want to grant. 4. Enter a JSON `where` clause in the **Condition** field. 5. Click **Create** to save. Conditions cannot be applied to localized fields and do not support `search` capabilities. ![Conditions](/images/docs/user-guides/roles-and-permissions/setup-example-conditions.png) You need to maintain conditions manually. If a field is renamed or a referenced document ID changes, the condition becomes invalid. Update affected conditions whenever the underlying schema or content changes. The following examples show conditions applied to a `Post` model: - Grant access only to posts tagged with specific values: ```json { "tags_contains_some": ["GraphQL", "SEO"] } ``` - Extend the above to also include posts with no tags: ```json { "OR": [{ "tags_contains_some": ["GraphQL", "SEO"] }, { "tags": null }] } ``` ![PAT Post Tag Conditions](/images/docs/api-reference/basics/pat-post-tag-conditions.png) - Restrict access to posts related to a specific author by ID: ```json { "author": { "id_in": ["ckadqgca800ix011230ailipe"] } } ``` For this to work, the token or role also needs read access on the `Author` model. You can optionally restrict that access to a single document: ```json { "id": "ckadqgca800ix011230ailipe" } ``` ![PAT Post Author Conditions](/images/docs/api-reference/basics/pat-post-author-conditions.png) ## What's next - [Authorization](/docs/api-reference/basics/authorization): Public API permissions, PATs, and endpoints. - [Roles and permissions](/docs/getting-started/access-and-permissions/user-roles-and-permissions): Create and configure roles, assign permissions, and set up role-based access. - [API access](/docs/getting-started/access-and-permissions/api-access): Manage API endpoints, Permanent Auth Tokens, and content permissions. --- # Team members Source: https://hygraph.com/docs/getting-started/access-and-permissions/manage-team-members The **Project Members** screen gives you an overview of everyone on your project team and the roles they are assigned to. From here you can invite new members, change role assignments, remove members, and navigate to role details. To access this screen, navigate to **Project Settings > Team > Members**. ![Project team members](/images/docs/user-guides/project-guides/projectsettings-team-members.png) ## Invite team members You must invite a user to the project before you can assign them to a role. 1. Click **Invite members** at the top right of the **Project Members** screen. 2. Enter the user's **Email address** and select their **Role** from the dropdown. The dropdown lists all roles currently configured in your project. [Learn more about roles and permissions](/docs/getting-started/access-and-permissions/user-roles-and-permissions). 3. Click **Add to list** to add the user to the invite queue. Repeat for additional members if needed. 4. Click **Invite** to send the invitation. ![Add team members](/images/docs/user-guides/project-guides/projectsettings-team-members-add.png) ### Resend invitations For accounts not yet registered in Hygraph, wait at least 15 minutes before resending an invitation to the same email address. You can resend to the same address a maximum of three times within a 24-hour period. ## Change a member's role 1. Navigate to **Project Settings > Team > Members** and locate the user in the list. 2. Open the context menu for that user and select **Change role**. 3. The role list for that member becomes editable. Select a role from the list to add it. 4. Click **Update** to save the changes. ![Remove a team member from a role](/images/docs/user-guides/roles-and-permissions/change-role.png) ## Remove a member's role 1. Navigate to **Project Settings > Team > Members** and locate the user in the list. 2. Open the context menu for that user and select **Change role**. 3. The role list for that member becomes editable. Click the **×** next to a role name to remove it. 4. Click **Update** to save the changes. ![Remove a team member from a role](/images/docs/user-guides/roles-and-permissions/remove-role.png) ## Remove a member from the project 1. Navigate to **Project Settings > Team > Members** and locate the user in the list. 2. Open the context menu for that user and select **Remove from project**. 3. Confirm the action in the dialog that appears. This action is permanent and cannot be undone. The user will lose access to the project immediately. ![Remove team member from a project](/images/docs/user-guides/project-guides/team-member-remove-from-project.png) ## View role details To view the permissions associated with a role that a member belongs to: 1. Open the context menu for the team member. 2. Select **View role**. If the member has multiple roles, select the specific role you want to inspect. This takes you to the [Roles & Permissions](/docs/getting-started/access-and-permissions/user-roles-and-permissions) screen for that role, where you can see the list of assigned members and the content and Management API permissions configured for it. ![View role](/images/docs/user-guides/project-guides/team-member-view-role.png) ## What's next - [Roles](/docs/getting-started/access-and-permissions/user-roles-and-permissions): Create and configure roles, assign permissions, and set up role-based access. --- # Management API permissions Source: https://hygraph.com/docs/getting-started/access-and-permissions/management-api-permissions Management API permissions govern access to your project's structural and configuration elements, such as schema, environments, roles, webhooks, and so on. They control what users assigned to a role can see in the Hygraph UI, and what actions Permanent Auth Tokens (PATs) can perform through the Management API. The same set of permissions is available for both [custom roles](/docs/getting-started/access-and-permissions/user-roles-and-permissions#custom-roles) and [Permanent Auth Tokens (PATs)](/docs/getting-started/access-and-permissions/api-access#authenticated-requests-permanent-auth-tokens), but their defaults and behaviors differ. Management API permissions are **global**. They apply across all environments in a project. ## Roles vs PATs Understanding how Management API permissions behave differently for roles and PATs will save you a lot of confusion when configuring access. - **Roles** - Management API permissions primarily control **UI visibility**. Granting a permission shows a button, tab, or section to users assigned to that role. Revoking it hides it. If a user lacks a permission, the effect is visible in the interface. They may not see a button, get an error when accessing a restricted area, or in some cases be logged out. - Defaults cover the read permissions needed to navigate the Hygraph UI correctly. Anything beyond that must be added manually. - **PATs** - Management API permissions control **API access**. If a token lacks a permission, the API call fails with an insufficient permissions error. There is no UI involved. A token created with **Add token** starts with no Management API permissions. Enable each one you need. This distinction matters because some permissions are **UI-only**. They control what users see in the Hygraph interface but have no effect on what a PAT can do programmatically. The most common example is **Create new entries**, which shows or hides the **Add entry** button in the content editor. Granting this to a PAT does nothing, because PATs do not interact with the UI and content creation is handled by the Content API, not the Management API. Hiding a Studio button does not block the Content API. If the role has the matching [content permission](/docs/getting-started/access-and-permissions/content-api-permissions), the user can still perform that action by calling the API. ## Schema Schema create and read permissions are defaults for custom roles, but **Can see schema view** is not. That permission is under [UI visibility](#ui-visibility). A new custom role therefore has **Read existing models**, but still does not see **Schema** in Studio until you enable **Can see schema view**. ### Models | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Create new models | `MODEL_CREATE` | With **Can see schema view**, shows **Add** for models. | Required for model creation mutations (`createModel`, `createSimpleModel`). | Yes | | Read existing models | `MODEL_READ` | With **Can see schema view**, shows models in Schema. Also required for **Project Settings > Access > Content API**. | Required to read models and for most schema mutations that reference existing models. | Yes | | Update existing models | `MODEL_UPDATE` | Edit the **Settings** tab of models. Also needs schema and model read. | Required for model update mutations. | No | | Delete existing models | `MODEL_DELETE` | Shows **Delete** for models. | Required for model deletion mutations. | No | ### Fields | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Read existing fields | `FIELD_READ` | Shows the **Fields** tab. | Required to read fields and for field related schema operations. | Yes | | Create new fields | `FIELD_CREATE` | Shows the **Fields** side panel in Schema. | Required for field creation mutations on models and components. | Yes | | Update existing fields | `FIELD_UPDATE` | Shows **Edit** on field cards and the drag and drop handle. Also needs schema and model read. | Required for field update mutations. | No | | Delete existing fields | `FIELD_DELETE` | Allows deleting fields. Also needs schema and model read. | Required for field deletion mutations. | No | ### Components | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Create new components | `COMPONENT_CREATE` | With **Can see schema view**, shows **Add** for components. | Required for component creation mutations. | Yes | | Read existing components | `COMPONENT_READ` | With **Can see schema view**, shows components in Schema. | Required to read components and for component related schema operations. | Yes | | Update existing components | `COMPONENT_UPDATE` | Edit component **Settings**. Controls schema level component metadata only. | Required for component update mutations. | No | | Delete existing components | `COMPONENT_DELETE` | Shows **Delete** in a component's context menu. | Required for component deletion mutations. | No | ### Remote sources | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Read remote sources | `REMOTE_SOURCE_READ` | With **Can see schema view**, shows remote sources in Schema. | Required to read remote sources and for related schema operations. | Yes | | Create remote sources | `REMOTE_SOURCE_CREATE` | With **Can see schema view**, shows **Add** for remote sources. | Required for remote source creation mutations. | Yes | | Update remote sources | `REMOTE_SOURCE_UPDATE` | Edit remote source **Settings**. Without it, **Save** is hidden. | Required for remote source update mutations. | No | | Delete remote sources | `REMOTE_SOURCE_DELETE` | Shows **Delete** for remote sources. | Required for remote source deletion mutations. | No | ### Enumerations | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Read existing enumerations | `ENUMERATION_READ` | With **Can see schema view**, shows enumerations in Schema. | Required to read enumerations and for enumeration related schema operations. | Yes | | Create new enumerations | `ENUMERATION_CREATE` | With **Can see schema view**, shows **Add** for enumerations. | Required for enumeration creation mutations. | Yes | | Update existing enumerations | `ENUMERATION_UPDATE` | Edit enumeration details. Also needs schema and enumeration read. | Required for enumeration update mutations. | No | | Delete existing enumerations | `ENUMERATION_DELETE` | Shows **Delete** in the enumeration details context menu. | Required for enumeration deletion mutations. | No | ### Taxonomies | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Read taxonomy | `TAXONOMY_READ` | With **Can see schema view**, required to open taxonomies and view **Settings**. | Required for taxonomy queries and taxonomy related mutations. | Yes | | Create taxonomy | `TAXONOMY_CREATE` | With **Can see schema view**, shows **Add Taxonomy**. Also needs **Create taxonomy node**. | Required for taxonomy creation mutations. | Yes | | Update taxonomy | `TAXONOMY_UPDATE` | Without it, taxonomy **Settings** are read-only. | Required for taxonomy update mutations. | No | | Delete taxonomy | `TAXONOMY_DELETE` | Shows **Delete** in the taxonomy details context menu. | Required for taxonomy deletion mutations. | No | | Read taxonomy node | `TAXONOMY_NODE_READ` | With **Can see schema view**, browse taxonomy **Nodes**. | Required for taxonomy node queries and node related mutations. | Yes | | Create taxonomy node | `TAXONOMY_NODE_CREATE` | Shows **Add child node**. Together with **Create taxonomy**, enables **Add Taxonomy**. | Required for taxonomy node creation mutations. | Yes | | Update taxonomy node | `TAXONOMY_NODE_UPDATE` | Add child nodes, rename nodes, or move nodes. | Required for taxonomy node update mutations. | No | | Delete taxonomy node | `TAXONOMY_NODE_DELETE` | Shows **Delete** next to the taxonomy node. | Required for taxonomy node deletion mutations. | No | ## Content **Read public content views** and **Read public view groups** together gate the **Content** tab. Neither is a default for custom roles. Sidebar views also need [Read on DRAFT](/docs/getting-started/access-and-permissions/content-api-permissions#permission-actions) per model. **Assets** needs the same pair plus **Read** on the Asset model. ### Content views | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Create public content views | `CONTENTVIEW_CREATE` | Shows **Save as new view**. | Required for custom content view creation mutations. | No | | Read public content views | `CONTENTVIEW_READ` | Required with **Read public view groups** to open **Content**. | Required to read `environment.contentView` and `environment.contentViews`. | No | | Update public content views | `CONTENTVIEW_UPDATE` | Shows **Update view** and **Update custom view**. | Required to update custom content views. | No | | Update system content views | `CONTENTVIEW_SYSTEM_UPDATE` | Update a model's **default** content view. | Required to update **system / default** content views. | No | | Delete public content views | `CONTENTVIEW_DELETE` | Shows **Delete custom view**. | Required to delete **custom** content views. | No | ### View groups | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Create public view groups | `VIEW_GROUP_CREATE` | Shows **Add view group**. | Required for view group creation mutations. | No | | Read public view groups | `VIEW_GROUP_READ` | Required with **Read public content views** to open **Content**. | Required to read `environment.viewGroups` and related fields. | No | | Update public view groups | `VIEW_GROUP_UPDATE` | Shows **Edit view group**. | Required for view group update mutations. | No | | Delete public view groups | `VIEW_GROUP_DELETE` | Shows **Delete view group**. | Required for view group deletion mutations. | No | ### Locales | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Read locales | `LOCALE_READ` | Required to access locale information. Missing it returns an error. | Required for locale queries and locale dependent Management API operations. | Yes | | Create locales | `LOCALE_CREATE` | Shows **Add** in **Project Settings > General > Locales**. | Required for locale creation mutations. | No | | Update locales | `LOCALE_UPDATE` | Without it, locales are read-only. | Required for locale update mutations. | No | | Delete locales | `LOCALE_DELETE` | Shows **Delete** in **Project Settings > General > Locales**. | Required for locale deletion mutations. | No | ### Studio content actions These permissions do **not** grant Content API access. For roles, they show or hide Studio buttons. For PATs, they have no useful effect. You need to configure [content permissions](/docs/getting-started/access-and-permissions/content-api-permissions#permission-actions). **Read existing entries** does not control the **Content** or **Assets** tabs. Use **Read public view groups** and **Read public content views**. | Permission name | Action | For roles | For PATs | Alternative | |-----------------|--------|-----------|----------|-------------| | Read existing entries | `CONTENT_READ` | Deprecated. Does not show **Content** or **Assets**. | Deprecated. No effect on Content API reads. | **Read public view groups** + **Read public content views**; **Assets** also needs Asset model **Read** | | Create new entries | `CONTENT_CREATE` | Shows **Add entry**. | Deprecated. Does not grant Content API **Create**. | [Content permissions — Create](/docs/getting-started/access-and-permissions/content-api-permissions#permission-actions) | | Delete existing entries | `CONTENT_DELETE` | Shows **Delete**. | Deprecated. Does not grant Content API **Delete**. | [Content permissions — Delete](/docs/getting-started/access-and-permissions/content-api-permissions#permission-actions) | | Publish non-published entries | `CONTENT_PUBLISH` | Shows Publish in Studio. | Deprecated. Does not grant Content API **Publish**. | [Content permissions — Publish](/docs/getting-started/access-and-permissions/content-api-permissions#permission-actions) | | Update existing non published entries | `CONTENT_UPDATE` | **Save** on draft / non-published entries. | Deprecated. Does not grant Content API **Update**. | [Content permissions — Update](/docs/getting-started/access-and-permissions/content-api-permissions#permission-actions) | | Update published entries | `CONTENT_UPDATE_PUBLISHED` | **Save** on published entries; also required for Unpublish and for Publish to work across Studio. | Deprecated. Does not grant Content API **Update** or **Unpublish**. | [Content permissions — Update or Unpublish](/docs/getting-started/access-and-permissions/content-api-permissions#permission-actions) | ## Environments & stages **Read existing environments** is a custom role default. Do not disable it. Without it, users cannot open the project. The environment selector is under [UI visibility](#ui-visibility). ### Environments | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Read existing environments | `ENVIRONMENT_READ` | Required to access the project. Together with **Can see environment selector**, shows **Environments** in Project Settings. | Required for environment scoped queries and mutations for the PAT's environment. | Yes | | Create new environment | `ENVIRONMENT_CREATE` | Enables **Clone** in **Project Settings > General > Environments**. | Required for environment clone/create mutations. | No | | Update an existing environment | `ENVIRONMENT_UPDATE` | Edit environments in Studio and through the Management API. | Required for environment update mutations. | No | | Delete an existing environment | `ENVIRONMENT_DELETE` | Enables **Delete** in **Project Settings > General > Environments**. | Required for environment deletion mutations. | No | | Promote an existing environment | `ENVIRONMENT_PROMOTE` | Shows **Promote**. | Required for promote mutations. Restoring from backup uses `ENVIRONMENT_BACKUP_RESTORE`. | No | ### Content stages | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Read stages | `STAGE_READ` | Required to access content stage information. Shows **Project Settings > General > Content Stages**. | Required for stage queries and content stage configuration. | Yes | | Create stages | `STAGE_CREATE` | Shows **Add Stage**. | Required for content stage creation mutations. | No | | Update stages | `STAGE_UPDATE` | Edit content stages. | Required for content stage update mutations. | No | | Delete stages | `STAGE_DELETE` | Without it, **Delete** on a content stage throws an error. | Required for content stage deletion mutations. | No | ### Environment backups | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Create new environment backup | `ENVIRONMENT_BACKUP_CREATE` | Create an environment backup. | Required for backup creation mutations. | No | | Read existing environment backups and their details | `ENVIRONMENT_BACKUP_READ` | Shows **Project Settings > Governance > Backup & Recovery**. | Required to query environment backups and their metadata. | No | | Update an existing environment backup | `ENVIRONMENT_BACKUP_UPDATE` | Update an environment backup. | Required for backup update mutations. | No | | Delete an existing environment backup | `ENVIRONMENT_BACKUP_DELETE` | Delete an environment backup. | Required for backup deletion mutations. | No | | Restore an existing environment backup to a standard environment | `ENVIRONMENT_BACKUP_RESTORE` | Restore a backup into a standard environment. | Required to restore a backup into a standard environment. | No | ## Team & access Showing the **Members** and **Roles** screens also requires the matching [UI visibility](#ui-visibility) permissions. These content permission rows control who can manage permission configuration in Settings. ### Members | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Invite a user into an existing project | `USER_INVITE` | Shows **Invite members** in **Project Settings > Team > Members**. | Required for member invite mutations. | No | | Assign a role to a user | `USER_ASSIGNROLE` | Shows **Change role** in **Members**. Also shows **Assign members** on a role. | Required for role assignment mutations. | No | | Remove a user from an existing project | `USER_REMOVE` | Shows **Remove** and **Remove from project**. Also required to delete agents from **AI Hub > Agents**. | Required for `remove` member and `deleteAgent` mutations. | No | ### Roles | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Create new roles | `ROLE_CREATE` | Shows **Add custom role**. | Required for custom role creation mutations. | No | | Update existing roles | `ROLE_UPDATE` | Without it, roles open read-only and editing content permissions fails. | Required for role update mutations, including management and content permissions on roles. | No | | Delete an existing role | `ROLE_DELETE` | Shows **Delete** for custom roles. | Required for custom role deletion mutations. | No | ### Permanent auth tokens | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Can create new permanent auth tokens | `PAT_CREATE` | Shows **Add token** on **Permanent Auth Tokens**. | Required for PAT creation mutations. Grant on a token only when automation manages other PATs. | No | | Can read existing permanent auth tokens | `PAT_READ` | Shows **Permanent Auth Tokens** in **Project Settings > Access**. For the API Playground, also grant **Can use the playground**. | Required for PAT read/list operations. | No | | Can update existing permanent auth tokens | `PAT_UPDATE` | Shows **Edit** in the PAT context menu. | Required for PAT update mutations. | No | | Can delete existing permanent auth tokens | `PAT_DELETE` | Shows **Delete** in the PAT context menu. | Required for PAT deletion mutations. | No | ### Content permissions | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Can create content permissions | `CONTENT_PERMISSION_CREATE` | Shows **Add permissions** on the public Content API, roles, and PATs. | Required to create content permission rows via the Management API. | No | | Can read content permissions | `CONTENT_PERMISSION_READ` | Shows the **Content permissions** block for roles and PATs. | Required to read content permission configuration. | No | | Can update content permissions | `CONTENT_PERMISSION_UPDATE` | Shows **Edit** on content permissions. | Required to update content permission rows. | No | | Can delete content permissions | `CONTENT_PERMISSION_DELETE` | Shows **Delete** on content permissions. | Required to delete content permission rows. | No | ## Automation ### Webhooks | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Create new webhooks | `WEBHOOK_CREATE` | Shows **Add webhook**. | Required for webhook creation mutations. | No | | Read existing webhooks | `WEBHOOK_READ` | Shows **Project Settings > Automation > Webhooks**. | Required for webhook queries. | No | | Update existing webhooks | `WEBHOOK_UPDATE` | Shows **Edit** for webhooks. | Required for webhook update mutations. | No | | Delete an existing webhook | `WEBHOOK_DELETE` | Shows **Delete** for webhooks. | Required for webhook deletion mutations. | No | ### Workflows **Read workflow** is a custom role default. It shows **Project Settings > Governance > Workflows**. | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Read workflow | `WORKFLOW_READ` | Access workflow information and related UI. | Required for workflow queries and related Management API operations. | Yes | | Create a new workflow | `WORKFLOW_CREATE` | Create a workflow. | Required for workflow creation mutations. | No | | Update a workflow | `WORKFLOW_UPDATE` | Update a workflow. | Required for workflow update mutations. | No | | Delete a workflow | `WORKFLOW_DELETE` | Delete a workflow. | Required for workflow deletion mutations. | No | | Create a new workflow step | `WORKFLOW_STEP_CREATE` | Create a workflow step. | Required for workflow step creation mutations. | No | | Update a workflow step | `WORKFLOW_STEP_UPDATE` | Update a workflow step. | Required for workflow step update mutations. | No | | Delete a workflow step | `WORKFLOW_STEP_DELETE` | Delete a workflow step. | Required for workflow step deletion mutations. | No | ### Netlify | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Can trigger a netlify build for an existing integration | `NETLIFY_TRIGGER_BUILD` | Trigger a Netlify build. | Required for Netlify build trigger mutations. | No | ## Apps & integrations **Apps** in the Studio sidebar is controlled by **Can see apps section** under [UI visibility](#ui-visibility). The permissions below control install, edit, and uninstall. ### App installations | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Can add app installations | `APP_INSTALLATION_CREATE` | Shows the **Explore apps** banner. Projects without this permission do not appear in the project selector for new installs. | Required for app installation mutations. | No | | Can update app installations | `APP_INSTALLATION_UPDATE` | Shows **Edit** on app cards. | Required for app installation update mutations. | No | | Can delete app installations | `APP_INSTALLATION_DELETE` | Shows **Uninstall app** in the app card context menu. | Required for app uninstall mutations. | No | ### Integrations | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Can add new integrations to an existing project | `INTEGRATION_CREATE` | Create an integration. | Required for integration creation mutations. | No | | Can see existing integrations in an existing project | `INTEGRATION_READ` | Read existing integrations. | Required for integration queries. | No | | Can update existing integrations in an existing project | `INTEGRATION_UPDATE` | Update an integration. | Required for integration update mutations. | No | | Can delete existing integrations in an existing project | `INTEGRATION_DELETE` | Delete an integration. | Required for integration deletion mutations. | No | ### Extensions | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Can add new extension to an existing project | `EXTENSION_CREATE` | Create an extension. | Required for extension creation mutations. | No | | Can see existing extensions in an existing project | `EXTENSION_READ` | Read existing extensions. | Required for extension queries. | No | | Can update existing extensions in an existing project | `EXTENSION_UPDATE` | Update an extension. | Required for extension update mutations. | No | | Can delete existing extensions in an existing project | `EXTENSION_DELETE` | Delete an extension. | Required for extension deletion mutations. | No | ## AI Hub ### Agents **Remove an agent** and **Delete an agent config** appear in Roles & Permissions but have no effect today. Leave them disabled. Deleting an agent uses [**Remove a user from an existing project**](#members). | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Create an agent | `AGENT_CREATE` | Shows **Add agent** in **AI Hub > Agents**. | Required for `createAgent` mutations. | No | | Read agent config | `AGENT_CONFIG_READ` | Required to open **AI Hub > Agents** and agent KPIs when agents are enabled. | Required for agent configuration queries. | No | | Update an agent config | `AGENT_CONFIG_UPDATE` | Edit or enable/disable agents. | Required for `updateAgent` mutations. | No | | Trigger an agent run | `AGENT_RUN` | Required to manually trigger agents from the content editor or content table. | **UI-only**. Not used for workflow-triggered runs. | No | | Delete an agent config | `AGENT_CONFIG_DELETE` | No effect. | No effect. `deleteAgentConfig` is not implemented. Use `deleteAgent`, which checks **Remove a user from an existing project**. | No | | Remove an agent | `AGENT_REMOVE` | No effect. | No effect. `removeAgentFromProject` is not implemented. | No | ### Guidelines | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Create AI guidelines | `AI_GUIDELINE_CREATE` | Create an AI guideline. | Required for AI guideline creation mutations. | No | | Read AI guidelines | `AI_GUIDELINE_READ` | Required to open **AI Hub > Guidelines** when the feature is enabled. | Required for AI guideline queries. | No | | Update AI guidelines | `AI_GUIDELINE_UPDATE` | Edit AI guidelines. | Required for AI guideline update mutations. | No | | Delete AI guidelines | `AI_GUIDELINE_DELETE` | Delete AI guidelines. | Required for AI guideline deletion mutations. | No | ## Tags Tags is a Labs feature. | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Read tags | `ENTRY_TAG_READ` | Required to open tags in Studio. | Required for tag queries. | Yes | | Create tags | `ENTRY_TAG_CREATE` | Shows **New tag**. | Required for tag creation mutations. | Yes | | Update tags | `ENTRY_TAG_UPDATE` | Rename or move tags. | Required for tag update mutations. | No | | Delete tags | `ENTRY_TAG_DELETE` | Delete tags. | Required for tag deletion mutations. | No | ## UI visibility These permissions only decide whether a part of the Studio interface is visible, such as a sidebar entry, a settings screen, or the environment selector. They do not grant access to the data behind that screen, which still depends on the permissions listed in the other sections. They have no effect on a PAT. | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Can see Team Member Settings | `VIEW_TEAM_MEMBER_SETTINGS` | Shows **Project Settings > Team > Members**. | **UI-only** | No | | Can see Role & Permissions Settings | `VIEW_ROLE_PERMISSION_SETTINGS` | Shows **Project Settings > Team > Roles & Permissions**. | **UI-only** | No | | Can see schema view | `VIEW_SCHEMA` | Required to see **Schema**. Also needs at least one of **Read existing models**, **Read existing components**, **Read existing enumerations**, or **Read remote sources**. | **UI-only** | No | | Can see project settings | `VIEW_PROJECT_SETTINGS` | Shows **Project Settings** in the sidebar. Individual screens still need their own permissions. | **UI-only** | Yes | | Can see apps section | `VIEW_APPS` | Shows **Apps** in the sidebar. Install, edit, and uninstall still need the [app installation](#app-installations) permissions. | **UI-only** | Yes | | Can see environment selector | `VIEW_ENVIRONMENT_SELECTOR` | Shows the environment selector. Together with **Read existing environments**, shows **Project Settings > General > Environments**. | **UI-only** | Yes | ## Project & governance | Permission name | Action | For roles | For PATs | Custom role default | |-----------------|--------|-----------|----------|---------------------| | Change the name, picture and description of a project | `PROJECT_UPDATE` | **Project Settings > General > Project** is otherwise read-only. Included by default for Admin and Developer system roles. | Required for project metadata mutations (name, picture, description, support access). | No | | Can use the playground | `PLAYGROUND_USE` | Shows **API Playground** and **Preview in Playground** in the content editor and Assets. | **UI-only** | No | | Read audit logs | `AUDIT_LOGS_READ` | Shows **Project Settings > Governance > Audit Logs**. | **UI-only** | No | | Allows starting, scheduling, and lifting content freezes | `MANAGE_CONTENT_FREEZE` | Shows **Project Settings > Governance > Content Freeze** and the **Manage freeze** banner action. | Required for `startContentFreeze` and `liftContentFreeze`. | No | | Allows managing experimental features and their role assignments | `MANAGE_EXPERIMENTAL_FEATURES` | Manage lab / experimental features. | Required for experimental feature management mutations. | No | | Read observability data | `OBSERVABILITY_READ` | Shows **Project Settings > General > Usage**. | Required for observability read operations on the Management API. | No | ## What's next - [Permission combinations by job](/docs/getting-started/access-and-permissions/permission-combinations-by-job): Combined permission sets by job. - [Roles](/docs/getting-started/access-and-permissions/user-roles-and-permissions): Create a custom role and assign members. - [API access](/docs/getting-started/access-and-permissions/api-access): PATs and the public Content API. - [Content permissions](/docs/getting-started/access-and-permissions/content-api-permissions): Read, Create, Update, Publish, and related rules. --- # Permission combinations by job Source: https://hygraph.com/docs/getting-started/access-and-permissions/permission-combinations-by-job Use this page when a job needs **more than one permission**. For detailed information about what each permission does on its own, see [Content permissions](/docs/getting-started/access-and-permissions/content-api-permissions) and [Management API permissions](/docs/getting-started/access-and-permissions/management-api-permissions). For information on how to create a role and toggle permissions in Studio, see [Roles](/docs/getting-started/access-and-permissions/user-roles-and-permissions). ## Permission layers Most of the scenarios below combine the following layers: | Layer | What it controls | Scope | |-------|------------------|--------| | **Management API permissions** | What the role can **see** in Studio (tabs, buttons, settings screens). Some also authorize Management API calls. | Global | | **Content permissions** | What the role can **do** to entries (read, create, update, delete, publish, unpublish, read versions). | Per environment | A role can have content **Read** and still see an empty **Content** tab. This isn't always intuitive because the two permissions that unlock sidebar visibility live under Management API permissions. **Add entry**, **Save**, **Publish**, and **Delete** each require a separate [Studio content actions](/docs/getting-started/access-and-permissions/management-api-permissions#studio-content-actions) permission on top of everything above. A button can render and still fail the moment someone clicks it, the same way a form can look submittable and reject on submit. **Read existing environments** is required to open the project. Do not disable it. ## Content The first row below covers opening **Content** in the sidebar. Every other row assumes that access already exists. | Job | Management API permissions | Content permissions | |-----|----------------------------|---------------------| | See **Content** | `Read public view groups` and `Read public content views` | **Read** on **DRAFT** for each model that should appear | | Create an entry | `Create new entries` | `Read`, `Create`, and `Read versions`. Also `Read` on `DRAFT` and the default locale. | | Edit a draft | `Update existing non published entries` | `Read`, `Update`, and `Read versions` | | Edit a published entry | `Update published entries` | `Read`, `Update`, and `Read versions` | | Publish | `Publish non-published entries` and `Update published entries` | `Read` and `Publish` (Draft plus the target stage). Add `Read versions` if publishing from the entry form. | | Unpublish | `Update published entries` | `Read` on all stages and `Unpublish`. Add `Read versions` if unpublishing from the entry form. | | Delete | `Delete existing entries` | `Read` on all stages, `Delete`, and `Unpublish` on every stage except Draft. Add `Read versions` if deleting from the entry form. | | **Update view** | `Update public content views` and `Update system content views` | Not applicable. Views aren't scoped by content permissions. | ## Assets The first row below covers opening **Assets** in the sidebar. The second row assumes that access already exists. | Job | Management API permissions | Content permissions | |-----|----------------------------|---------------------| | See **Assets** | `Read public view groups` and `Read public content views` | `Read` on the **Asset** model | | Upload or create assets | `Create new entries` | `Read` and `Create` on the **Asset** model. Also `Read` on `DRAFT` and the default locale. Add `Read versions` if creating from the asset editor. | ## Schema | Job | Minimum Management API permissions | |-----|-----------------------------------| | Open Schema | `Can see schema view`, plus at least one of `Read existing models`, `Read existing components`, `Read existing enumerations`, or `Read remote sources`. Taxonomy read permissions do not count. | | Browse models | `Can see schema view` and `Read existing models` | | Add a model | `Can see schema view`, `Read existing models`, and `Create new models` | | Edit model settings | `Can see schema view`, `Read existing models`, and `Update existing models` | | Edit model fields | Everything in `Edit model settings`, plus `Update existing fields`. Add `Create new fields` or `Delete existing fields` to add or remove fields. | | Open taxonomies | Everything in `Open Schema`, plus `Read taxonomy`. Add `Read taxonomy node` to open taxonomy nodes. | | Create a taxonomy | Everything in `Open taxonomies`, plus `Create taxonomy` and `Create taxonomy node`. | ## Apps | Job | Minimum Management API permissions | |-----|-----------------------------------| | See **Apps** | `Can see apps section` | | Install an app | `Can see apps section` and `Can add app installations` | | Edit an app installation | `Can see apps section` and `Can update app installations` | | Uninstall an app | `Can see apps section` and `Can delete app installations` | ## Project settings | Job | Minimum Management API permissions | |-----|-----------------------------------| | Open environments | `Read existing environments` and `Can see environment selector` | | Clone an environment | `Read existing environments`, `Can see environment selector`, and `Create new environment` | | Open Content API settings | `Can see project settings` and `Read existing models` | | Manage Members | `Can see Team Member Settings`, plus `Invite a user into an existing project`, `Assign a role to a user`, or `Remove a user from an existing project` as needed | | Manage Roles | `Can see Role & Permissions Settings`, plus `Create new roles`, `Update existing roles`, or `Delete an existing role` as needed | | Add, edit, or delete content permissions | `Can read content permissions`, plus `Can create content permissions`, `Can update content permissions`, or `Can delete content permissions` as needed | | Duplicate a custom role | `Create new roles` and an available custom role seat | | Manage Permanent Auth Tokens | `Can read existing permanent auth tokens`, plus create, update, or delete as needed | | Use API Playground with content | `Can use the playground`, plus the content `Read` the query needs | | Restore a backup | `Read existing environment backups and their details` and `Restore an existing environment backup to a standard environment` | ## AI | Job | Minimum Management API permissions | |-----|-----------------------------------| | Edit guidelines | `Read AI guidelines` and `Update AI guidelines` | | Create an agent | `Read agent config` and `Create an agent` | | Edit or enable an agent | **Read agent config** and **Update an agent config** | | Delete an agent | `Remove a user from an existing project`. `Delete an agent config` and `Remove an agent` have no effect today. | | Manually run an agent from the content editor or table | `Trigger an agent run`, plus Content access | ## API access without Studio Studio UI flags do not apply to tokens. Configure [content permissions on the PAT](/docs/getting-started/access-and-permissions/api-access#configure-content-permissions) or for [unauthenticated requests to the Content API](/docs/getting-started/access-and-permissions/content-api-permissions#set-up-unauthenticated-access-to-the-content-api). | Job | Minimum | |-----|---------| | Create or update content with a PAT | Matching content permissions: `Create` / `Update` (and `Read`). Do not rely on `Create new entries` or other UI-only Management API flags. | | Modify schema with a PAT | Management API action permissions such as `Read existing models` and `Create new models`. | ## Content reviewer Start from a new custom role. The following are read-only permissions in Studio. **Management API** - `Read public view groups` - `Read public content views` **Content** (per environment) - Model: All, or the models they should see - `Read`: all locales, `DRAFT` (and `PUBLISHED` if they should compare stages) - **Read versions** ## Content editor Everything in **Content reviewer**, plus the permissions below. These permissions allow create and update in Studio, but do not include publish. **Management API** - `Create new entries` - `Update existing non published entries` - `Update published entries` if they save entries that are already published **Content** - `Create` - `Update` - Default locale included ## Content publisher Everything in **Content editor**, plus the permissions below. These permissions allow publish and unpublish in Studio. **Management API** - `Publish non-published entries` - `Update published entries` (also required to unpublish in Studio) **Content** - `Publish` (from Draft to the target stage) - `Unpublish` if they should take content off a stage ## Schema developer Start from a new custom role. The permissions below are for Schema only; they do not open Content. **Management API** - `Can see schema view` - `Read existing models`, `Read existing components`, `Read existing fields`, `Read existing enumerations`, `Read remote sources`, `Read taxonomy`, and `Read taxonomy node` - `Create new models`, `Create new components`, `Create new fields`, `Create new enumerations`, `Create remote sources`, `Create taxonomy`, and `Create taxonomy node` - Add update and delete permissions only for the schema elements they should change - `Can use the playground` if they should test queries in Studio Do not enable `Read public view groups` or `Read public content views` unless they also need Content. ## Project settings admin Start from a new custom role. The permissions below are for Project Settings only; they do not open Content or Schema. Add the screens they should manage, for example: - `Can see project settings` - `Read existing webhooks` (and create, update, or delete as needed) - `Can see Team Member Settings` and `Invite a user into an existing project` - `Can see Role & Permissions Settings` and `Update existing roles` - `Can read existing permanent auth tokens` ## What's next - [Roles](/docs/getting-started/access-and-permissions/user-roles-and-permissions): Create custom roles and assign members. - [Content permissions](/docs/getting-started/access-and-permissions/content-api-permissions): Actions, locales, stages, conditions, and how to scope a permission. - [Management API permissions](/docs/getting-started/access-and-permissions/management-api-permissions): Full list of Management API permissions. - [API access](/docs/getting-started/access-and-permissions/api-access): Configure content permissions on a Permanent Auth Token. - [Set up unauthenticated access to the Content API](/docs/getting-started/access-and-permissions/api-access#unauthenticated-requests-content-api): Serve content without a token. --- # Roles Source: https://hygraph.com/docs/getting-started/access-and-permissions/user-roles-and-permissions Roles determine what users can see and do in your Hygraph project. Each role carries a set of **content permissions**, which govern access to content entries, and **Management API permissions**, which determine what a user can do in the UI and through the API. **Content permissions are environment-specific.** Their configuration is applied per environment. If you are working with multiple environments, configure content permissions separately for each one. **Management API permissions are global.** They apply across all environments in a project. Hygraph provides five built-in system roles and supports custom roles for projects on enterprise plans. To access roles and permissions, navigate to **Project Settings > Team > Roles & Permissions**. ![Roles and Permissions overview](/images/docs/user-guides/roles-and-permissions/roles-and-permissions-overview.png) ## System roles System roles are built into every Hygraph project. They cannot be edited or deleted. | Role | Rights | |-------------|----------------------------------------------------------------------------------------------| | Owner | All Admin rights, plus the ability to change billing settings and delete the project. | | Admin | All Developer rights, plus the ability to manage team members and create or update projects. | | Developer | All Editor rights, plus the ability to create, update, and delete models and enumerations. | | Editor | All Contributor rights, plus the ability to delete content. | | Contributor | Ability to create and update content. | For system roles, **Admins** and **Owners** can: - Click a system role to view its permissions. Permissions for system roles are read-only. - Click **Assign members** on the role row to assign team members to that role. ## Custom roles Custom roles are available on Enterprise plans only. Custom roles let you define exactly what a user can see and do, without exposing features that are not relevant to their work. Only project **Admins** and **Owners** can create and manage custom roles. When configuring a custom role, always include the **Read** and **Read versions** content permissions. Without **Read**, users cannot open content entries. Without **Read versions**, versioning will not display correctly in the content editor. ### Create a custom role 1. Under **Custom roles**, click **Add custom role**. 2. Enter a **Name** for the role and optionally a **Description**. 3. Click **Create**. ![Add custom role](/images/docs/user-guides/roles-and-permissions/add-custom-role.png) The new role is created with default **Management API** permissions. It does not get content permissions yet. Click the role to add content permissions and adjust Management API permissions. ### Configure content permissions Content permissions determine what actions users can perform on content entries in the content editor. Custom roles have no content permissions by default. At a minimum, a custom role that uses the content editor need the following permissions: - **Read** access on the `User` system model. This is important for custom roles that interact with the UI, as user attribution fields (`createdBy`, `updatedBy`, and `publishedBy`) will not display without these permissions. Missing these permissions can also cause `not allowed` errors when mutating content from the content editor. See [System fields: User fields](/docs/api-reference/schema/system-fields#user-fields) for more information. - **Read versions**. This is required for versioning to display correctly in the content editor.
Add a permission
1. Click on the custom role in the roles table to open its permissions screen. 2. Under **Content permissions**, click **Add permissions**. If there are no content permissions yet, the empty state offers **Add permissions** and **Initialize defaults**. **Initialize defaults** grants **Read** on all models for all locales, scoped to the default public content delivery stage. - Use the **Model** dropdown to select the model to apply permissions to. Select **All** to apply them across all models. - Use the checkboxes to select the actions to grant. Some actions reveal additional options for **Locales** and **Stages**. 5. Click **Create** to save.
For what each action means, including locales and stages, see [Content permissions](/docs/getting-started/access-and-permissions/content-api-permissions#permission-actions). For how to scope a permission by model, locale, stage, environment, or condition, see [Scope content permissions](/docs/getting-started/access-and-permissions/content-api-permissions#scope-content-permissions).
Edit a permission
**Edit** is available only when the permission has locale or stage settings. Click the context menu for a custom role, and click **Edit**. You can update the locale or stage for the content permission. ![Edit permissions](/images/docs/user-guides/api-access/edit-permissions.png)
Delete a permission
Click the context menu for a custom role, and click **Delete**. Confirm the deletion in the dialog that appears. This action is permanent and cannot be undone. ![Delete permissions](/images/docs/user-guides/api-access/delete-permissions.png)
### Configure Management API permissions Management API permissions control both API access and UI visibility. 1. Click on the custom role in the roles table. 2. Under **Management API**, the table lists all available permissions. Enabled permissions are toggled on. You can perform the following actions: - Use **Group by Domain** or **Group by Action** to group the list. - Filter the list with **All permissions**, **Enabled permissions**, or **Disabled permissions**. - Use the toggles to enable or disable individual permissions. - Use the checkboxes to select multiple permissions, and then enable or disable them in bulk. Some Management API permissions are **UI-only** and have no effect on a PAT. For what each permission does for roles versus tokens, see [Management API permissions](/docs/getting-started/access-and-permissions/management-api-permissions). ## Manage custom role ![Manage custom role](/images/docs/user-guides/roles-and-permissions/manage-custom-role.png) ### View permissions Click the custom role to view the content and Management API permissions associated with it. You can: - Sort permissions alphabetically by model or action. - Filter permissions by action, model, locale, and stage. - Assign new members to the role by clicking **Assign members** at the top right. Permissions for system roles are read-only. To add or change permissions on that screen, see [Configure content permissions](#configure-content-permissions) and [Configure Management API permissions](#configure-management-api-permissions). For combined permission sets for a job, such as a read-only reviewer or a publisher, see [Permission combinations by job](/docs/getting-started/access-and-permissions/permission-combinations-by-job). ### Assign members Before assigning a user to a role, they must be [invited to the project](/docs/getting-started/access-and-permissions/manage-team-members#invite-team-members). To assign project members to a custom role: 1. Under the **Custom roles** section, click **Assign members** next to the role name. 2. Select one or more team members using the checkboxes. 3. Click **Save changes**. ### Duplicate role System roles cannot be duplicated. To duplicate a custom role: 1. Under the **Custom roles** section, click **...** to open the context menu for the role. 2. Click **Duplicate role**. The copied role includes the source role's Management API permissions and content permissions in every environment. Assigned members are not copied. Duplicating a role requires the **Create new roles** permission, and a custom role seat must be available on the plan. ### Delete role System roles cannot be deleted. You can permanently delete a custom role. To delete a custom role: 1. Under the **Custom roles** section, click **...** to open the context menu for the role. 2. Select **Delete role**. 3. Confirm the deletion in the popup. This action cannot be undone. ## What's next - [Team members](/docs/getting-started/access-and-permissions/manage-team-members): Invite members and manage project access. - [Content permissions](/docs/getting-started/access-and-permissions/content-api-permissions): Detailed reference for content permission rules, limits, and conditions. - [Management API permissions](/docs/getting-started/access-and-permissions/management-api-permissions): Full reference for all Management API permission options. --- # Hygraph account settings Source: https://hygraph.com/docs/getting-started/account-settings Account settings let you manage the core details of your Hygraph account, including personal information and notifications. These settings apply across all projects you have access to. At the top right of the screen, click your avatar and select **Account settings**. ![Account settings](/images/docs/getting-started/fundamentals/project-directory-supports-and-settings.png) Account settings apply to your user account. Project-specific configuration is managed separately within each project. ## Profile information Your profile contains basic information associated with your account, such as your name and email address. This information is used across Hygraph for identification and collaboration. Some fields, like your email address, may be managed by your identity provider if your organization uses Single Sign-On (SSO). ## Notifications Use notification settings to choose whether Hygraph notifies you about replies, mentions, assignments, and status updates through email or in-app notifications. You can adjust these preferences at any time to match your workflow. ## Update your password To change your account password, you will need to log out and choose **Forgot your password** on the login page to receive an email for setting a new one. If you've logged in with GitHub or Google, you can change your password there and you'll be logged in automatically with Hygraph. ## Delete your account You can permanently delete your Hygraph account from the account settings page. Deleting your account is irreversible and removes your personal access to Hygraph. Any projects you own will be deleted, while projects you are a member of will remain active for other members. --- # Learn about Hygraph Source: https://hygraph.com/docs/getting-started/index Hygraph is a GraphQL-native structured content platform, also referred to as a headless CMS, built to model, govern, and deliver content across every brand, channel, and market. This page covers what Hygraph is, how the platform is structured, and what capabilities are available to your team. ## What is Hygraph? Hygraph gives development and content teams a single, governed foundation for structuring, creating, and delivering content programmatically. Content is modeled as structured entities and relationships, not pages, so it can be reused, governed, and delivered anywhere: any frontend, any backend, through one GraphQL API. Content Federation extends that same API to external systems, so data from commerce platforms, PIMs, and third-party APIs is queryable alongside your own content. Your schema lives in one place. Your content can come from anywhere. Your frontend is your choice. ## How it works Hygraph projects follow a consistent structure across three layers. ### Schema You define your content structure by creating models, adding fields, and configuring relationships between them. Models can include reusable components, remote data sources, and sidebar widgets for custom editorial tools. ### Content Once your schema is set, teams create and manage entries in the Content Editor. Entries move through configurable stages (such as `Draft` and `Published`), and you can schedule publishing, bundle entries into releases, and assign collaborative workflows to ensure the right people review content before it goes live. Editors can preview content in context using Live Preview, and make field-level edits directly from a frontend page using Click-to-Edit. ### Delivery Hygraph exposes your content through a globally distributed GraphQL API. You query your own content and federated remote sources in a single request. ## Platform capabilities The sections below map the capabilities available across Hygraph by area. ### Content modeling The **Schema Builder** supports scalar fields, relational fields, union types, enumerations, components, and remote sources. Conditional fields let you show or hide fields in the editor based on values entered elsewhere in the entry, keeping complex models manageable for editorial teams. Use taxonomies to define hierarchical classification structures, such as tags, categories, and facets that apply consistently across content types. Use variants to define audience-specific versions of content entries without duplicating content entries. ### Editorial experience The content editor supports localization, scheduled publishing, release management, and collaborator view, which shows when another user is editing the same entry. Quick filters and Content Finder reduce the time it takes to locate entries across large projects. ### AI capabilities AI Assist lets editors generate, improve, and localize content through natural language prompts inside the entry form. AI Agents automate repetitive editorial tasks, such as translation, SEO analysis, and content summarization, directly inside your Hygraph project. You can trigger an agent manually on selected entries, or configure it to run automatically when an entry moves through a workflow step. When an agent completes its task, the entry enters a read-only review state where the editor can approve or revert each field change before editing resumes. ### Visual editing Live Preview displays a preview of your frontend alongside the content editor, so changes are visible without publishing. With Click-to-Edit, editors can hover over any element in your preview, click **Edit**, and the editor opens at the exact field. ### Asset management The Assets manager handles uploads, transformations, and delivery for images, video, and documents. Asset transformations, such as resizing, format conversion, and cropping, apply at the API level via URL parameters, so you don't need a separate tool to manage image delivery. ### Content Federation Remote sources connect external REST or GraphQL APIs to your Hygraph schema. Once configured, remote data is queryable through the same GraphQL endpoint as your local content. Top-level remote fields let you fetch remote content directly without anchoring it to a Hygraph model. ### Developer tools Hygraph provides a Content API for content delivery, a Management SDK for programmatic schema and content operations, and Webhooks for event-driven integrations. The App Framework lets you build custom field extensions, sidebar elements, and third-party integrations tailored to your project. The MCP Server exposes Hygraph to MCP-compatible AI tools. ### Access and governance Granular permissions let administrators define role-based access at the model, field, stage, and locale level. Content workflows add structured approval steps to content creation, so entries pass through defined checkpoints before publication. Audit logs record all actions, including those performed via app tokens, PATs, and third-party integrations. ## Use cases Hygraph is built for organizations where content spans more than one brand, market, or system. - **Multi-Brand Enterprises**: One governed content foundation for every brand, replacing separate CMS instances per brand. - **eCommerce Across Regions & Languages**: Structured product content, localized and delivered via GraphQL, without duplicating entries per market. - **AI Operations & Agentic Content**: A structured content graph AI agents can reliably consume, connected via MCP within governed boundaries. - **B2B Portals & Audience Targeting**: Role-based content delivery, by account, region, or entitlement, built into the model, not the frontend. ## What's next - [Quickstart](/docs/getting-started/quickstart): Create your first project, define a schema, and query content. - [Studio walkthrough](/docs/getting-started/studio-walkthrough): Get oriented with the Hygraph interface and where key features live. - [eCommerce tutorial](/docs/getting-started/tutorial/tutorial-overview): Build a complete Hygraph project from schema to connected frontend. --- # Migrate to Hygraph Source: https://hygraph.com/docs/getting-started/migrating-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](/docs/api-reference/basics/authorization#permanent-auth-tokens) 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](/images/docs/getting-started/fundamentals/plan-your-schema.png) Work through the following questions: - What models and fields do you currently have, and how do they map to [Hygraph's field types](/docs/api-reference/schema/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: ```csv oldId,firstName,lastName 1,Stephen,King 2,Frank,Herbert 3,Brian,Herbert 4,Kevin,Anderson 5,Agatha,Christie 6,Haruki,Murakami 7,Isaac,Asimov ``` Hygraph supports over a dozen [field types](/docs/api-reference/schema/field-types), from strings, booleans, and dates to polymorphic union types and remote field resolvers. You get a small set of [system fields](/docs/api-reference/schema/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](/images/docs/getting-started/fundamentals/create-your-schema.png) 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](/docs/api-reference/management-sdk/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:** ```bash npm install @hygraph/management-sdk ``` **Initialize the client:** ```ts const { Client } = require('@hygraph/management-sdk'); // endpoint is your High Performance Content API URL // found in Project Settings > Endpoints > High Performance Content API const client = new Client({ authToken, endpoint, name, // optional }); ``` Use `createModel` to create a model: ```js client.createModel({ apiId: '', apiIdPlural: '', description: '', displayName: '', }); ``` To create two models, `Author` and `Book`: ```js 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: ```js client.createSimpleField({ apiId: '', description: '', displayName: '', embeddableModels: '', embedsEnabled: '', formConfig: '', formExtension: '', formRenderer: '', isHidden: '', isList: '', isLocalized: '', isRequired: '', isTitle: '', isUnique: '', migrationValue: '', parentApiId: '', position: '', tableConfig: '', tableExtension: '', tableRenderer: '', type: SimpleFieldType.STRING, validations: '', visibility: '', }); ``` To add a required string field to the `Author` model: ```js 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: ```js // migration.js const { Client, SimpleFieldType } = require('@hygraph/management-sdk'); const client = new Client({ authToken: '', endpoint: '', }); // Create the Author model client.createModel({ apiId: 'Author', apiIdPlural: 'Authors', displayName: 'Author', }); // Add firstName field to Author client.createSimpleField({ parentApiId: 'Author', apiId: 'firstName', displayName: 'First Name', type: SimpleFieldType.STRING, }); // Add lastName field to Author client.createSimpleField({ parentApiId: 'Author', apiId: 'lastName', displayName: 'Last Name', type: SimpleFieldType.STRING, }); // Preview all changes before committing const changes = client.dryRun(); console.log(changes); ``` Run the script from the command line: ```bash 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: ```js 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](/docs/api-reference/management-sdk/management-sdk-field-examples) for instructions. **Additional resources:** - [Management SDK quickstart](/docs/api-reference/management-sdk/management-sdk-quickstart) - [Management SDK methods reference](/docs/api-reference/management-sdk/management-sdk-methods-reference) - [Management SDK full example](/docs/api-reference/management-sdk/management-sdk-example) - [Batch migrations](/docs/api-reference/management-sdk/management-sdk-batchmigration) ### 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](/docs/getting-started/quickstart) 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](/images/docs/getting-started/fundamentals/api-endpoints-location.png) ### 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 `createAsset` mutations instead. - **Legacy asset system:** Uses a dedicated HTTP upload endpoint at `/upload` appended 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](/docs/api-reference/basics/authorization#permanent-auth-tokens) 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](/docs/api-reference/basics/environments) and [authorization](/docs/api-reference/basics/authorization) settings as all other content in your project. After uploading, [publish your assets](/docs/api-reference/assets/publishing-assets) before they can be served alongside published content. For full asset upload documentation, see [Uploading assets](/docs/api-reference/assets/uploading-assets). **Upload by file — Hygraph Asset Management** First, create the asset via mutation to receive the upload URL and credentials: ```graphql mutation createAsset { createAsset(data: {}) { id url upload { status expiresAt error { code message } requestPostData { url date key signature algorithm policy credential securityToken } } } } ``` ```json { "data": { "createAsset": { "id": "clt47n0t600j807vvirlzi1xx", "url": "https://eu-central-1.graphassets.com/clpqzrnm4007e01t810b59ir4/clt47n0t600j907vveibipmov", "upload": { "status": "ASSET_CREATE_PENDING", "expiresAt": "2024-02-27T12:38:49+00:00", "error": null, "requestPostData": { "url": "https://eu-1-assets-delivery-hg75hf.s3.eu-central-1.amazonaws.com", "date": "20240227T101349Z", "key": "clpqzrnm4007e01t810b59ir4/upload/...", "signature": "c17e7b1c5d4af665a8fc74421fae53b72e94bb19e85e7befd1eb79b865bef7d2", "algorithm": "AWS4-HMAC-SHA256", "policy": "eyJleHBpcmF0aW9uIjo...", "credential": "ASIAVQRE3VMEWGY5C2XL/20240227/eu-central-1/s3/aws4_request", "securityToken": "IQoJb3JpZ2luX2Vj..." } } } } } ``` Then upload the file using the credentials from the response: ```bash 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** ```graphql mutation uploadByUrl { createAsset( data: { uploadUrl: "https://images.unsplash.com/photo-1682687218147-9806132dc697" } ) { id url } } ``` **Upload by file — legacy asset system** ```bash curl -XPOST -H "Authorization: Bearer {YOUR_PAT_VALUE}" -F fileUpload=@picture.jpg https://[region].hygraph.com/v2/[projectId]/[environment]/upload ``` ```js // File must use the .mjs extension, as node-fetch is an ESM-only package. import fetch, { FormData, fileFrom } from 'node-fetch'; const form = new FormData(); form.set('fileUpload', await fileFrom('path/to/file.png')); fetch(`${process.env.HYGRAPH_URL}/upload`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.HYGRAPH_ASSET_TOKEN}`, }, body: form, }) .then((res) => res.json()) .then((data) => console.log(JSON.stringify(data, null, 2))) .catch((err) => console.log(err)); ``` ```js const HYGRAPH_URL = ''; const HYGRAPH_ASSET_TOKEN = ''; async function upload() { const input = document.getElementById('fileUpload'); const file = input.files[0]; const form = new FormData(); form.append('fileUpload', file); // Do not expose HYGRAPH_ASSET_TOKEN in front-end code in production. // Use a backend service to handle uploads and keep the token server-side. const response = await fetch(`${HYGRAPH_URL}/upload`, { method: 'POST', headers: { Authorization: `Bearer ${HYGRAPH_ASSET_TOKEN}`, }, body: form, }); const data = await response.json(); console.log(JSON.stringify(data, null, 2)); } ``` ```json { "filename": "pexels-photo-1170986.jpeg", "mimetype": "image/jpeg", "size": 32476, "width": 500, "height": 750, "url": "https://media.graphassets.com/P3TkBzxyQLupgDWNFydB", "id": "ckfdz530o0001ip92cdr3bbmj" } ``` **Upload by remote URL — legacy asset system** ```bash curl -XPOST -d url=https://media.graphassets.com/P3TkBzxyQLupgDWNFydB https://[region].hygraph.com/v2/[projectId]/[environment]/upload ``` ```js // File must use the .mjs extension, as node-fetch is an ESM-only package. import fetch from 'node-fetch'; fetch(`${process.env.HYGRAPH_URL}/upload`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.HYGRAPH_ASSET_TOKEN}`, 'Content-Type': 'application/x-www-form-urlencoded', }, body: `url=${encodeURIComponent( 'https://media.graphassets.com/P3TkBzxyQLupgDWNFydB' )}`, }) .then((res) => res.json()) .then((data) => console.log(JSON.stringify(data, null, 2))) .catch((err) => console.log(err)); ``` ```json { "filename": "pexels-photo-1170986.jpeg", "mimetype": "image/jpeg", "size": 32476, "width": 500, "height": 750, "url": "https://media.graphassets.com/J9BOEF3OSuuSXDhvriQa", "id": "ckgs20b80017109547vfev24c" } ``` ### Content entries To find your Content API endpoint, go to **Project Settings > Access > Endpoints > High Performance Content API**. Use [GraphQL mutations](/docs/api-reference/content-api/mutations#auto-generated-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](#step-1-explore-your-current-data): ```js // Import necessary libraries const { GraphQLClient, gql } = require('graphql-request'); const csvToJson = require('csvtojson'); require('dotenv').config(); // Initialize GraphQL client const client = new GraphQLClient(process.env.HYGRAPH_ENDPOINT, { headers: { authorization: `Bearer ${process.env.HYGRAPH_TOKEN}`, }, }); // Build a mutation from a data row function createMutation(data) { return gql` mutation MyMutation { createAuthor(data: { firstName: "${data.firstName}", lastName: "${data.lastName}", oldId: "${data.oldId}" }) { id } } `; } // Run the migration async function run() { // Load and parse the CSV const data = await csvToJson().fromFile('./data.csv'); // Build mutations from each row const mutations = data.map((item) => createMutation(item)); // Execute each mutation with a 1-second delay between requests mutations.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](/docs/api-reference/basics/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. 1. **Convert:** Use Hygraph's HTML-to-Slate AST converter to transform your existing rich text into the correct AST format. 2. **Import:** Use a `create` mutation with a `RichTextAST` variable to import the converted content. ```graphql mutation createArticle($title: String, $content: RichTextAST) { createArticle(data: { title: $title, content: $content }) { title content { raw } } } ``` ```json { "title": "Working with the Hygraph Rich Text field", "content": { "children": [ { "type": "paragraph", "children": [ { "text": "Hygraph boasts an impressive collection of " }, { "href": "https://hygraph.com/docs/api-reference/schema/field-types", "type": "link", "children": [{ "text": "Field Types" }] }, { "text": " that you can use when content modeling." } ] } ] } } ``` 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](/docs/api-reference/content-api/mutations#create-entries) 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](/docs/api-reference/content-api/mutations#create-entries), then wire them together using [update mutations](/docs/api-reference/content-api/mutations#update-entries) or [update many mutations](/docs/api-reference/content-api/mutations#update-many). This approach is more straightforward but requires more total mutations. Option 2 requires more mutations to be sent. Review the [rate limits](/docs/api-reference/basics/rate-limits) documentation before choosing your approach. ```graphql # Create a book with a new author (one relation) mutation createOneRelation { createBook( data: { name: "Rose madder" slug: "rose-madder" price: 30 author: { create: { name: "Stephen King", slug: "stephen-king" } } } ) { id name author { name } } } # Create a book with multiple new authors mutation createManyRelations { createBook( data: { name: "The road to Dune" slug: "the-road-to-dune" price: 30 authors: { create: [ { name: "Frank Herbert", slug: "frank-herbert" } { name: "Brian Herbert", slug: "brian-herbert" } { name: "Kevin Anderson", slug: "kevin-anderson" } ] } } ) { id name author { name } } } ``` ```graphql # Create a book and connect to an existing author mutation createAndConnectOne { createBook( data: { name: "Rose madder" slug: "rose-madder" price: 30 author: { connect: { slug: "stephen-king" } } } ) { id name author { name } } } # Create a book and connect to multiple existing authors mutation createAndConnectMany { createBook( data: { name: "The road to Dune" slug: "the-road-to-dune" price: 30 authors: { connect: [ { slug: "frank-herbert" } { slug: "brian-herbert" } { slug: "kevin-anderson" } ] } } ) { id name author { name } } } ``` ## 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](/docs/api-reference/basics/rate-limits). ## What's next - [Management SDK](/docs/api-reference/management-sdk/management-sdk): Full reference for creating and updating schema elements programmatically. - [Content API mutations](/docs/api-reference/content-api/mutations): Reference for create, update, connect, and nested mutations. - [Upload assets](/docs/api-reference/assets/uploading-assets): Full documentation for asset uploads, including both legacy and current asset systems. - [Rate limits](/docs/api-reference/basics/rate-limits): Understand request limits before running large-scale imports. - [Field types](/docs/api-reference/schema/field-types): Reference for all field types available in Hygraph. --- # Quickstart Source: https://hygraph.com/docs/getting-started/quickstart This Quickstart walks you through creating your first Hygraph project, from setup to querying content. If you’re looking for a deeper, end-to-end walkthrough, check out our [Full Tutorial: Build Your First eCommerce Project](/docs/getting-started/tutorial/tutorial-overview). It expands on these concepts with guided, step-by-step lessons that take you from project creation all the way to connecting a frontend. ## Register 1. You'll need a Hygraph account to get started. Go to https://app.hygraph.com/signup. 2. Select one of the available options: - GitHub - Google - Email, password, and name 3. Select the checkbox to agree to the terms of service and privacy policy, and click **Continue**. 4. You'll receive a verification email. Click on the provided link and log in using your credentials. After logging in, you'll land in your project directory. This is where you’ll find all your projects and create new ones. Any pending project invites are available at the top of the screen. If you’d like a quick overview of the Hygraph interface and navigation, see the [Studio walkthrough](/docs/getting-started/studio-walkthrough). ## Create a project When you log in, you'll see a list of projects you own or have been invited to. If you’re new to Hygraph, this list may be empty. You can either create a blank project or use our Showcase project to explore how Hygraph works. Click **Get started** to start exploring the Showcase project. Starting with the Showcase project helps you get a feel for how the platform works. ![First screen](/images/docs/getting-started/fundamentals/first-screen.png) To add a blank project, follow these steps: 1. If you've just signed up, click **Start from scratch**. Otherwise, click **Add project**. 2. Select your plan. Choose Hobby, Enterprise, or start a 30-day trial. See our Pricing page for details. 3. Provide a project name, an optional description, and a content region. If you need a custom region, contact sales. - Hygraph stores your content in the region you select and delivers it globally via our CDN. Learn more in the [Caching](/docs/api-reference/basics/caching) documentation. 4. Click **Add project**. Hygraph redirects you to the project homepage. ![Blank new project](/images/docs/getting-started/fundamentals/new-project-blank.png) ## Create a model Let's create a model for our products. Think of a model as a database table or collection in NoSQL that defines the schema and structure of your content. 1. Open the **Schema** builder. 2. Click **+ Add** and create a new model named `Product`, keeping the suggested API IDs. 3. Optionally add a description for editors and API users. 4. Click **Add Model**. You’ve added a **Product** model to your GraphQL schema. With the model in place, you can now start adding fields. ## Add fields to your model Fields define the data you can store on a model. Each field uses one of Hygraph’s supported [field types](/docs/api-reference/schema/field-types). For this Quickstart, you'll add three fields to the `Product` model: - `Name` - `Price` - `Image` ### Name field 1. Select the **Single line text** field from the sidebar. 2. Set the **Display name** to **Name**. 3. Under **Validations**, enable **Make field required**. 4. Click **Add**. ### Price field 1. Select the **Number** field from the sidebar. 2. Set the **Display name** to **Price**. 3. Under **Validations**, enable **Make field required**. 4. Click **Add**. ### Image field 1. Select the **Asset picker** field from the sidebar. 2. Set the **Display name** to **Image**. 3. Enable **Allow multiple assets**. This lets you add more than one image to each product entry. 4. Click **Add**. Every project includes an **Asset** model by default. It is used to store images and other files. Learn more about [working with assets](/docs/developer-guides/assets/work-with-assets). ### System fields Hygraph automatically manages [system fields](/docs/api-reference/schema/system-fields) such as `id`, `createdAt`, and `publishedAt`. To view system fields, enable the **Show system fields** toggle in the **Fields** tab for your selected model. ![Show system fields](/images/docs/getting-started/fundamentals/show-system-fields-toggle.png) ## Create a content entry With your schema ready, it’s time to add content. ![Add entry](/images/docs/getting-started/fundamentals/add-entry-button.png) 1. Navigate to the **Content** editor in your Hygraph project. 2. Under the **Default views** list, select the **Product** view. If your project only has the **Product** model so far, this view will display automatically when you access the content editor. 3. Your content entries table for **Product** is currently empty. To create content, click **+ Add entry** at the top-right corner of the screen. 4. Enter details for your new product. The available inputs correspond to the fields you added to the model. - Required and multi-value fields are enforced by the schema. Learn more about [field validations](/docs/api-reference/schema/field-configuration#validations). - `Name` and `Price` were set to **required** in the schema, so the UI here reflects those constraints. 5. Now, upload one or more images for your product. Click **Add image**, and upload an asset from your computer. - `Image` allows multiple images to be uploaded since we allowed **multiple values** in the schema. 6. Click **Save** to keep the entry in **DRAFT**. ![Entry in DRAFT stage](/images/docs/getting-started/fundamentals/entry-draft-stage.png) ## Publish your content By default, all projects include the **DRAFT** and **PUBLISHED** [content stages](/docs/developer-guides/content/content-stages). Draft is commonly used for previews or staging environments, while Published represents live content. Publishing promotes an entry from **DRAFT** to **PUBLISHED** so it can be consumed via the API. 1. Click **Publish** at the top-right corner of the screen while editing your content entry to publish it. Once you click **Publish**, a confirmation modal displays. This modal will also include any related entries or assets that are currently in the **DRAFT** stage and may need publishing as well. 2. If you have unpublished referenced entries, select the **All entries** checkbox to include all related entries and assets in the **DRAFT** stage. Then, click **Publish**. 3. You can continue to make changes to your content entry, and then save it again as many times as you want without publishing. When you save but don't publish, it is marked as **outdated**. This means the published version differs from the latest draft in your Hygraph project. ![A blue Published pill indicates that the content entry is outdated](/images/docs/getting-started/fundamentals/outdated-content-entry.png) 4. You can repeat publishing outdated entries either by clicking the **Publish** button again, or by [scheduling for later](/docs/developer-guides/content/scheduled-publishing#how-to-schedule). Before saving changes you made to a content entry, the **Publish** button will read **Save & Publish** instead. Clicking **Save & Publish** saves and publishes the content at once, so make sure you only use it when the content is ready to go live. Check out the document on [content publishing](/docs/developer-guides/content/publishing-content) for more information. ## Query content For every model that you create, Hygraph automatically generates GraphQL queries to fetch content entries. You can test these queries in the [API Playground](/docs/api-reference/basics/api-playground). ![The API Playground](/images/docs/getting-started/fundamentals/api-playground.png) 1. Navigate to the **API Playground** in your Hygraph project. 2. As you type `product` in the API Playground, you'll see recommended queries to fetch single or multiple product entries, an individual product version, and the [connection query](/docs/api-reference/content-api/queries#fetching-with-relay) to fetch edges/nodes. 3. Enter the following query: ```graphql { products { id name price image { url fileName } } } ``` 4. Click the **Play** icon to run the query. - Since we enabled **Allow multiple assets** on the `image` field, the API will return our images within an array (denoted by `[]` in JSON), even if you upload only one image. - If you had unchecked **Allow multiple assets** in the schema, the `image` field would return a single object `{}` instead of an array `[]`. ```json { "data": { "products": [ { "id": "cmkcb1fu3itum07moq2f5pzjj", "name": "My product entry", "price": 2000, "image": [ { "url": "https://eu-west-2.graphassets.com/cmk6vvkkl0dzk07mj5law3czs/cmkci63gk05hv07mmqaf80haj", "fileName": "t-shirt-white.jpg" } ] } ] } } ``` Explore the full [API Reference](/docs/api-reference) for additional information on filtering, pagination, ordering, and asset transformations. Our [Full Tutorial: Build Your First eCommerce Project](/docs/getting-started/tutorial/tutorial-overview) offers the option to clone a project that you can use to practice queries. ## Mutate content For every model that you create, Hygraph automatically generates GraphQL mutations so you can create, update, delete, publish, and unpublish content entries. You can try out all mutations in the [API Playground](/docs/api-reference/basics/api-playground). 1. Navigate to the **API Playground** in your Hygraph project. 2. In the API Playground, you'll start with the following: ```graphql mutation { } ``` 3. Start typing `product` to see mutations for the `Product` model. For this example, we'll use the `updateProduct` mutation to modify the product entry we previously created using the UI. - Hover over the mutation to view its arguments and documentation. - Explore input types such as `ProductUpdateInput` to see available fields. ![updateProduct mutation](/images/docs/getting-started/fundamentals/update-product-mutation.png) 4. Use the `where` and `data` arguments to write the mutation. In this example, you’ll update the `price` field. - You'll need an `id` of the product you created previously to continue. You can copy it from the query results in the [Query content](#query-content) section. ```graphql mutation { updateProduct(where: { id: "" }, data: { price: 25 }) { id name price } } ``` 5. Click the **Play** icon to execute this mutation. The product entry is updated with the new `price` value. Our [Full Tutorial: Build Your First eCommerce Project](/docs/getting-started/tutorial/tutorial-overview) offers the option to clone a project that you can use to practice mutations. ## API access To access your content outside of Hygraph, you need to configure Content API permissions. 1. Navigate to **Project settings > Access > Content API**. 2. To create new permissions, click **Initialize defaults**. This sets `Read` permissions on all models on the **PUBLISHED** stage. This means that anyone can read published content via the Content API. You can also protect the API with [permanent auth tokens](/docs/api-reference/basics/authorization). Learn more in the [API access](/docs/getting-started/access-and-permissions/api-access) documentation. ![Content API permissions](/images/docs/getting-started/fundamentals/public-content-api-permissions.png) 3. Now that the API is public, let's test it. Go to **Project settings > Access > Endpoints**, and copy the **High Performance Content API** endpoint. This is the default Content API used for production reads. ![Content API URL](/images/docs/getting-started/fundamentals/content-api-url.png) 4. Paste this endpoint in your browser. 5. Run the query from the [Query content](/docs/getting-started/quickstart#query-content) section of this document. This is now publicly accessible on the web. - If you see any errors, verify that you've [published at least one `Product` content entry](#publish-your-content). ![Content publicly available](/images/docs/getting-started/fundamentals/content-publicly-available.png) ## Next steps | Document | About | |-------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| | [Full Tutorial: Build Your First eCommerce Project](/docs/getting-started/tutorial/tutorial-overview) | Build a complete e-commerce project from schema design to a connected frontend. | | [Roles and permissions](/docs/getting-started/access-and-permissions/user-roles-and-permissions) | Information on roles and permissions including system roles, custom roles, how to work with roles & permissions, and detailed examples. | --- # Hygraph Studio walkthrough Source: https://hygraph.com/docs/getting-started/studio-walkthrough This page walks through the Hygraph Studio interface so you know where everything lives before you start building. If you want a step-by-step guide to creating a project and querying content, start with the [Quickstart](/docs/getting-started/quickstart). ## Overview When you log in to your Hygraph account, you land in the project directory. This is the account-level view, separate from any individual project. Here you can find the following tabs at the top: - **Home** - **Your apps** - **Analytics** ### Home **Home** lists your active projects and any pending project invites. It also includes a Showcase project you can use to explore Hygraph features before building your own. ![Home](/images/docs/getting-started/fundamentals/projects-tab.png) ### Your apps **Your apps** is where you create and manage custom apps you have built using the Hygraph App Framework. Apps you create here can be installed into projects and shared with other users. ![Your apps](/images/docs/getting-started/fundamentals/project-directory-apps-tab.png) ### Analytics **Analytics** gives you a usage overview across all projects you have access to, scoped to the `master` environment. You can customize which projects appear in the list and which columns are shown, including plan, API calls, asset traffic, content entries, locales, and seats. You can perform the following tasks on this dashboard: - Click **Open** next to the project name to access the project. - Select **Adjust columns** to customize which columns you want to display. The following columns are available:
- Owner of the project - Plan - Region - Billing period - API calls - Asset traffic - Content models
- Components - Remote sources - Taxonomies - Content entries - Locales - Seats - Workflows
![Analytics](/images/docs/getting-started/fundamentals/project-analytics.png) ## Project sidebar Once you open a project, the left sidebar is your primary navigation. It contains the following sections. ![Hygraph Studio sidebar](/images/docs/getting-started/fundamentals/project-dashboard.png) ### Overview The project homepage. It surfaces recently updated schema elements, links to documentation, and video content. ### Schema The Schema builder is where you define the structure of your content. You create models, add fields, configure relationships, set up components, and connect remote sources here. | Action | Description | |---|---| | [Create a model](/docs/getting-started/quickstart#create-a-model) | Define a new content model and add fields to it. | | [Add fields to a model](/docs/getting-started/quickstart#add-fields-to-your-model) | Extend an existing model with new field types. | | [Add components](/docs/developer-guides/schema/components) | Create reusable field templates that can be embedded in multiple models. | | [Add remote sources](/docs/developer-guides/remote-data/remote-sources) | Connect external APIs so their content is queryable through the Hygraph API. | | [Add enumerations](/docs/developer-guides/schema/using-enumerations) | Define a fixed list of values for use in dropdown fields. | | [Customize the content entry sidebar](/docs/developer-guides/content/customize-sidebar) | Add or remove widgets from the content entry sidebar. | ### Content The Content editor is where you create, edit, review, and publish entries based on the models in your schema. It supports default and custom views, so you can organize your content workspace to match your editorial workflow. | Action | Description | |---|---| | [Create a content entry](/docs/getting-started/quickstart#create-a-content-entry) | Add a new entry based on an existing model. | | [Publish content](/docs/getting-started/quickstart#publish-your-content) | Make an entry available via the Content API for the `PUBLISHED` stage. | | [Update content](/docs/developer-guides/content/updating-content) | Edit an existing entry, whether published or in draft. | | [Duplicate content](/docs/developer-guides/content/duplicating-content) | Copy an entry to use as the basis for a new one. | | [Schedule publishing](/docs/developer-guides/content/scheduled-publishing) | Set a future date and time for an entry to publish or unpublish. | | [Delete content](/docs/developer-guides/content/deleting-content) | Remove entries individually or in bulk. | | [Access content views](/docs/developer-guides/content/access-created-content) | Navigate to and customize how your content list is displayed. | ### Assets The Assets manager is where you upload and store files used in content entries. Like the Content editor, it supports default and custom views. | Action | Description | |---|---| | [Add an asset entry](/docs/developer-guides/assets/add-asset-entry) | Upload a file and add metadata to it. | | [Upload assets](/docs/developer-guides/assets/upload-asset) | Bring files in from different sources. | | [Work with assets](/docs/developer-guides/assets/work-with-assets) | Manage your asset table, similar to working with content entries. | ### AI Hub AI Hub contains Hygraph's AI-related tooling for your project, including AI agents and Guidelines. It is distinct from **AI Assist**, which is the top-bar tool for generating and improving content inline within the Content editor. | Action | Description | |---|---| | [AI agents](/docs/hygraph-ai/ai-agents) | Create and manage AI agents for your project. | | [AI guidelines](/docs/hygraph-ai/ai-guidelines) | Create and manage AI guidelines for your project. | ### API Playground The API Playground lets you test queries and mutations against your project's API directly in Studio. Use it to verify that your schema is returning the data you expect before wiring up a frontend. | Action | Description | |---|---| | [Test queries](/docs/api-reference/content-api/queries) | Run GraphQL queries against your content API. | | [Test mutations](/docs/api-reference/content-api/mutations) | Create, update, or delete content via the API to verify behavior. | ### Apps The **Apps** section shows the apps installed in your current project environment. From here you can configure or uninstall them, or go to the Marketplace to browse and install more. This is different from the **Your apps** tab in the project directory, where you create and manage apps you have built yourself. | Action | Description | |---|---| | [Install apps](/docs/integrations) | Browse and install apps from the Marketplace. | ### Project Settings Project Settings is where you manage everything that applies to the project as a whole: API access, environments, locales, roles, billing, and team members. | Action | Description | |---|---| | [Manage project information](/docs/developer-guides/project/manage-project-info) | Edit project details, clone your project, enable public cloning, manage support access, leave the project, or delete it. | | [Manage environments](/docs/developer-guides/project/manage-project-environments) | Create and switch between isolated instances of your project. | | [Manage API access](/docs/getting-started/access-and-permissions/api-access) | Configure endpoints, content API permissions, and permanent auth tokens. | | [Configure webhooks](/docs/developer-guides/webhooks/webhooks-overview) | Set up webhooks to trigger external actions on content events. | | [Manage roles and permissions](/docs/getting-started/access-and-permissions/user-roles-and-permissions) | Control what different team members can see and do in your project. | | [Manage team members](/docs/getting-started/access-and-permissions/manage-team-members) | Add members and assign roles. | | [Manage locales](/docs/developer-guides/project/manage-project-locales) | Add languages to support localized content. | | [Manage content stages](/docs/developer-guides/content/content-stages) | Create custom workflow stages beyond Draft and Published. | | [Manage audit logs](/docs/developer-guides/project/audit-logs) | Review a full history of schema and content changes in your project. | | [Update billing](/docs/getting-started/update-billing) | Change your plan or update payment information. | | [Clone your project](/docs/developer-guides/project/clone-your-project) | Create a copy of your project's master environment. | | [Share your project](/docs/developer-guides/project/share-your-project) | Generate a public clone link for others to copy your project. | ## Top bar The top bar is visible across all project sections. It gives you access to account-level tools and contextual actions. ![Hygraph Studio top bar](/images/docs/getting-started/fundamentals/top-bar.png) | Item | What you can do | |---|---| | Project and environment | See the current project and environment. Use the dropdown to switch projects or environments. | | Plan indicator | View your current plan. Click to open the plan picker and upgrade. | | Search | Find content entries across your environment. | | Recently viewed | Return to entries you viewed recently. | | AI Assist | Generate, improve, and localize content inline within the content entry editor. Available on enabled projects only. | | Help | Access documentation, code examples, and the Hygraph Slack community. | | Contact Support | Reach the Hygraph support team. | | Notifications | View alerts and updates across all your Hygraph projects. Unread notifications show a red indicator on the bell icon. | | Profile | Access your account settings or log out. | ## What's next - [Quickstart](/docs/getting-started/quickstart): Create a project, define a schema, and query your first content entry. - [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview): Start building a full project in Hygraph, from schema to frontend. --- # Lesson 4.2 - Add components to your models Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-add-components-to-models In this lesson, you will attach the components built in lesson 4.1 to the `Product`, `Landing page`, and `Navigation` models. After this lesson, the schema is structurally complete. ## Product The `Product` model receives two component fields: `Product Variant` and `Related Products` as basic component fields. Both are basic because each field always contains a single, fixed component type — there is no editorial choice about which component fills the field. 1. In the Schema editor, open the `Product` model. 2. From the right sidebar, add a **Basic** component field with the following information, and click **Add** to save: | Field | Input | |---|---| | Display Name | Product Variant | | API ID | ProductVariant | | Select component | Product Variant | 3. Add a second **Basic** component field with the following information, and click **Add** to save: | Field | Input | |---|---| | Display Name | Related Products | | API ID | RelatedProduct | | Description | Add related products | | Select component | Related Products | Your Product model should now look like this: ![Finished Product model with fields](/images/docs/getting-started/product-model.png) ## Landing page The `Landing page` model receives a modular component field called `Stripes`. It is modular because editors need to choose which component fills each section, either a `Call to Action` or a `Product Grid`. Allowing multiple values means editors can add as many sections as needed, in any order. 1. In the Schema editor, open the **Landing page** model. 2. From the right sidebar, add a **Modular** component field with the following information, and click **Add** to save: | Field | Input | |---|---| | Display Name | Stripes | | API ID | stripes | | Description | Sections | | Allow multiple values | Select checkbox | | Select allowed components | Call to Action, Product Grid | Your Landing page model should now look like this: ![Finished Landing Page model with fields](/images/docs/getting-started/landing-page-model.png) ## Navigation The Navigation model was left incomplete in lesson 1.2. It has a Nav ID field but no way to hold navigation links. The Link component built in lesson 4.1 is what completes it. 1. In the Schema editor, open the **Navigation** model. 2. From the right sidebar, add a **Basic** component field with the following information, and click **Add** to save: | Field | Input | |---|---| | Display Name | Nav Link | | API ID | navLink | | Description | Navigation links | | Allow multiple values | Select checkbox | | Select component | Link | The **Allow multiple values** setting is what enables the navigation to hold multiple links. Each link added in the content editor is a separate instance of the Link component. Your `Navigation` model should now look like this: ![Finished Navigation model](/images/docs/getting-started/navigation-model.png) Every model has the fields, references, and component fields it needs. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 5.2 - Add remote fields Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-add-remote-fields In this lesson, you will add a remote field to the `Product` model. Remote fields fetch data from a remote source in the context of a specific model entry. The field uses a value from the entry itself, in this case `productSlug`, as the argument passed to the external API, so the reviews returned are always scoped to that product. This is different from a top-level remote field, which fetches remote data independently of any entry. That is covered in lesson 5.3. ## Add a remote field to the Product model You will use the `HyDemoAPI` remote source configured in lesson 5.1 to add a `Reviews` field to the **Product** model. 1. Open the **Product** model in the Schema editor and from the right sidebar, add a **REST** remote field. 2. Fill in the following information: | Field | Input | |---|---| | Display name | Reviews | | API ID | Auto-completed. Leave as is. | | Remote source | HyDemoAPI is selected by default. Leave as is. | | Method | GET is selected by default. Leave as is. | | Return type | Select `Reviews` from the dropdown | | Path | `/api/reviews/product/{{doc.productSlug}}` | The `Path` appends to the remote source base URL. `{{doc.productSlug}}` references the `productSlug` field on the current `Product` entry, which scopes the review data to that specific product. 3. Click **Add** to save. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 5.1 - Add a remote source Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-add-remote-source In this lesson, you will add a remote source to the project schema. Before this step, the schema only returns data stored in Hygraph. After it, the schema includes queryable types from an external REST API that can be fetched alongside Hygraph content. A remote source is a custom resolver entry point in the schema. It accepts field values from other Hygraph fields as arguments, which is what makes it possible to fetch reviews scoped to a specific product in lesson 5.2. ## Configure the remote source You will connect a REST API using the Hygraph demo API. 1. Navigate to the **Schema editor** and click **+Add** next to **Remote Sources**. 2. Fill in the following information: | Field | Input | |---|---| | Select remote source type | Custom source | | Display Name | HyDemoAPI | | Type | REST | | Base URL | `https://demo-api.hygraph.workers.dev` | The base URL is the root endpoint for all remote fields that use this source. Individual remote fields append their own paths to this base. 3. Click **Add** to save the remote source configuration before adding type definitions. ## Add custom type definitions REST APIs return fixed data structures. To query a REST API as if it were native GraphQL, Hygraph needs to know the shape of the data it will receive. Custom type definitions provide that shape using GraphQL SDL. SDL stands for Schema Definition Language. It is the syntax used to define types and their fields in a GraphQL schema. The type definitions added here describe the structure of the data the `HyDemoAPI` returns, so Hygraph can expose those types in the project's GraphQL schema. 1. For each type definition, click **+Add custom type definition** and paste the snippets: ```GraphQL type Review { id: Int name: String product: String rating: Float comment: String } ``` ```GraphQL type Reviews { data: [Review] } ``` 2. Click **Add Remote Source** to save the configuration. Your finished remote source should look like this: The `Reviews` type wraps a list of `Review` entries. These two types are used by the remote fields in lessons 5.2 and 5.3. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 5.3 - Add top-level remote fields Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-add-top-level-remote-fields In this lesson, you will add a top-level remote field to the **Query** system model and run a test query to confirm the remote source is working correctly. A top-level remote field fetches remote data outside the context of any model entry. Where the remote field added in lesson 5.2 only returns reviews for a specific product, a top-level remote field can return review data independently. This is useful for fetching all reviews, or for passing in an argument from the frontend rather than from a content entry. ## Add a top-level remote field You will add the field to the **Query** system model using the same `HyDemoAPI` remote source. ![Complete top-level remote field configuration](/images/docs/getting-started/top-level-remote-field.png) 1. Open the **Query** model in the Schema editor and from the right sidebar, add a **REST** remote field. 2. Fill in the following information: | Field | Input | |---|---| | Display name | Reviews | | API ID | Auto-completed. Leave as is. | | Remote source | HyDemoAPI is selected by default. Leave as is. | | Method | GET is selected by default. Leave as is. | | Return type | Select `Reviews` from the dropdown | | Input arguments | Click **+ Add input argument** to reveal the argument fields | | Input type | String | | API ID | productSlug | | Make field required | Select checkbox | | Path | `/api/reviews/product/{{args.productSlug}}` | The `Path` appends to the remote source base URL. The `{{args.productSlug}}` path argument is supplied by whoever runs the query: a frontend component, a developer testing in the API Playground, or any API client. This means the top-level remote field has no dependency on Hygraph content. It can be queried even if the `Product` model contains no entries at all. The remote field in [lesson 5.2](/docs/getting-started/tutorial/tutorial-add-remote-fields#add-a-remote-field-to-the-product-model) works differently. Its path uses `{{doc.productSlug}}`, which pulls the `productSlug` value from the specific `Product` entry being queried. The top-level remote field removes that dependency entirely. 3. Click **Add** to save. ## Test the top-level remote field Because the top-level remote field is not connected to a content entry, it can be tested immediately without creating any content first. 1. Navigate to the **API Playground**. 2. Run the following query: ```graphql query MyQuery { reviews(productSlug: "plaid-shirt") { data { comment id name product rating } } } ``` ```json { "data": { "reviews": { "data": [ { "comment": "After wearing this shirt for 2 days, I realized it was made of cotton. I am allergic to cotton.", "id": 3, "name": "Oregon Person", "product": "plaid-shirt", "rating": 1.5 }, { "comment": "This shirt is okay. It lost a button, but I sewed it back on.", "id": 6, "name": "Another Person", "product": "plaid-shirt", "rating": 3.5 }, { "comment": "I love this shirt. I wear it all the time.", "id": 7, "name": "Third Person", "product": "plaid-shirt", "rating": 4.5 } ] } } } ``` The response confirms the remote source is correctly configured. The Hygraph API returns external review data without any data migration and without a separate API call from the frontend. This is [Content Federation](/docs/core-concepts/content-federation) working as intended. The schema is now complete. Content creation starts in the next lesson. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 4.1 - Build components Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-build-components In this lesson, you will build all components the project needs. These components must exist before you can attach them to models in [Lesson 4.2](/docs/getting-started/tutorial/tutorial-add-components-to-models). Some components depend on others. Build them in the order they appear in this lesson. `Clothing`, `Shoes`, `Accessories`, and `Decor` must exist before `Product Variant`. `Button` must exist before `Call to Action`. ## Related Products The `Related Products` component enables product pages to display other products a buyer might be interested in. It contains a read-only title field and a reference field that connects to other `Product` entries. 1. In the Schema editor, click **+Add** next to **Components**. 2. Provide the following information, and click **Add Component** to save: | Field | Input | |---|---| | Display Name | Related Products | | API ID | RelatedProduct | | Plural API ID | RelatedProducts | 3. Add the following fields to the `Related Products` component: **Single line text** - `Title`: | Field | Input | |---|---| | Display name | Title | | Use as title field | Select checkbox | | Make field required | Select checkbox | | Set initial value | Select checkbox, and enter `Related Products` in the initial value field | | Field visibility | Read only | The read-only title with an initial value ensures every instance of this component displays the same heading without editors being able to change it. **Reference** - `Products`: | Field | Input | |---|---| | Reference type | Allow only one model to be referenced | | Model to reference | Product | | Reference directions | One-way reference | | Allow multiple Products per RelatedProduct | Select checkbox | | Display name | Products | | API ID | products | | Description | Add 4 related products here | | Field visibility | Read / Write | 4. Click **Add** to save. Your `Related Products` component should look like this: ![Related Products component](/images/docs/getting-started/related-products-component.png) ## Product type components The store sells four product types: clothing, shoes, accessories, and decor. Each type requires different fields. Rather than creating four separate `Product` models, you will use four components, one per product type, and nest them inside a modular `Product Variant` component. The content editor then presents only the fields relevant to the selected product type. These four components use the enumerations created in [Lesson 3.1](/docs/getting-started/tutorial/tutorial-configure-enumerations). ### Clothing 1. Click **+Add** next to **Components**. 2. Provide the following information, and click **Add Component** to save: | Field | Input | |---|---| | Display Name | Clothing | | API ID | Clothing | | Plural API ID | ClothingItems | 3. Add the following fields: **Enumeration** - `Size`: | Field | Input | |---|---| | Display name | Size | | API ID | Auto-completed. Leave as is. | | Enumeration | Clothes size | | Make field required | Select checkbox | **Enumeration** - `Color`: | Field | Input | |---|---| | Display name | Color | | Enumeration | Wearable items color | | Make field required | Select checkbox | Your Clothing component should look like this: ![Clothing component](/images/docs/getting-started/clothing-component.png) ### Shoes 1. Click **+Add** next to **Components**. 2. Provide the following information, and click **Add Component** to save: | Field | Input | |---|---| | Display Name | Shoes | | API ID | Shoe | | Plural API ID | Shoes | 3. Add the following fields: **Enumeration** - `Size`: | Field | Input | |---|---| | Display name | Size | | Enumeration | Shoes size | | Make field required | Select checkbox | **Enumeration** - `Color`: | Field | Input | |---|---| | Display name | Color | | Enumeration | Wearable items color | | Make field required | Select checkbox | Your Shoes component should look like this: ![Shoes component](/images/docs/getting-started/shoes-component.png) ### Accessories 1. Click **+Add** next to **Components**. 2. Provide the following information, and click **Add Component** to save: | Field | Input | |---|---| | Display Name | Accessories | | API ID | Accessory | | Plural API ID | Accessories | 3. Add the following field: **Enumeration** - `Color`: | Field | Input | |---|---| | Display name | Color | | Enumeration | Wearable items color | | Make field required | Select checkbox | Your Accessories component should look like this: ![Accessories component](/images/docs/getting-started/accessories-component.png) ### Decor 1. Click **+Add** next to **Components**. 2. Provide the following information, and click **Add Component** to save: | Field | Input | |---|---| | Display Name | Decor | | API ID | Decor | | Plural API ID | DecorItems | 3. Add the following field: **Enumeration** - `Color`: | Field | Input | |---|---| | Display name | Color | | Enumeration | Decor items color | | Make field required | Select checkbox | Your Decor component should look like this: ![Decor component](/images/docs/getting-started/decor-component.png) ## Product Variant The `Product Variant` component contains a modular component field that presents `Clothing`, `Shoes`, `Accessories`, or `Decor` based on the product type an editor selects. This is the component that makes a single `Product` model work for all four product types. 1. Click **+Add** next to **Components**. 2. Provide the following information, and click **Add Component** to save: | Field | Input | |---|---| | Display Name | Product Variant | | API ID | ProductVariant | | Plural API ID | ProductVariants | 3. Add the following field: **Modular component** - `Product type`: | Field | Input | |---|---| | Display name | Product type | | API ID | productType | | Description | Select the product type to reveal fields | | Select allowed components | Clothing, Shoes, Accessories, Decor | 4. Click **Add** to save. Your Product Variant component should look like this: ![Product Variant component](/images/docs/getting-started/product-variant-component.png) ## Button The `Button` component holds a text label and a URL. It is used inside the `Call to Action` component in the next step. 1. Click **+Add** next to **Components**. 2. Provide the following information, and click **Add** to save: | Field | Input | |---|---| | Display Name | Button | | API ID | Button | | Plural API ID | Buttons | 3. Add the following fields: **Single line text** - `Text`: | Field | Input | |---|---| | Display name | Text | | Localize field | Select checkbox | **Slug** - `URL`: | Field | Input | |---|---| | Display name | URL | | Match a specific pattern | Select checkbox, then select `URL` from the dropdown | | Custom error message | Input value does not match the expected format. | Your `Button` component should look like this: ![Button component](/images/docs/getting-started/button-component.png) ## Call to Action The `Call to Action` component is used as a page section on Landing pages. It embeds the `Button` component created in the previous step. 1. Click **+Add** next to **Components**. 2. Provide the following information, and click **Add Component** to save: | Field | Input | |---|---| | Display Name | Call to Action | | API ID | CallToAction | | Plural API ID | CallToActions | 3. Add the following fields: **Single line text** - `Heading`: | Field | Input | |---|---| | Display name | Heading | | Localize field | Select checkbox | **Rich Text** - `Body`: | Field | Input | |---|---| | Display name | Body | | Localize field | Select checkbox | **Asset picker** - `Image`: | Field | Input | |---|---| | Display name | Image | **Basic component** - `Button`: | Field | Input | |---|---| | Display name | Button | | Select component | Button | Your `Call to Action` component should look like this: ![CTA component](/images/docs/getting-started/cta-component.png) ## Product Grid The `Product Grid` component is used as a page section on Landing pages. It displays a headline, a description, and a set of `Product` references. 1. Click **+Add** next to **Components**. 2. Provide the following information, and click **Add Component** to save: | Field | Input | |---|---| | Display Name | Product Grid | | API ID | ProductGrid | | Plural API ID | ProductGrids | 3. Add the following fields: **Single line text** - `Headline`: | Field | Input | |---|---| | Display name | Headline | | Localize field | Select checkbox | **Rich Text** - `Description`: | Field | Input | |---|---| | Display name | Description | **Reference** - `Products`: | Field | Input | |---|---| | Reference type | Allow only one model to be referenced | | Model to reference | Product | | Reference directions | One-way reference | | Allow multiple Products per ProductGrid | Select checkbox | | Display name | Products | | API ID | products | | Field visibility | Read / Write | Your `Product Grid` component should look like this: ![Product Grid component](/images/docs/getting-started/product-grid-component.png) ## Link component The `Link` component is included in the cloned project. It already contains two fields: `Display text` and `External URL`. You need to add a `Reference` field to it that connects it to the `Blog post`, `Landing page`, and `Product` models. This reference field could not be included in the original clone because it references models that did not exist until lesson 1.2. **This is the same layered schema pattern seen in lesson 1.2.** Models and components are built in layers because some connections can only be made after the things they connect exist. 1. In the Schema editor, under the **Components** section, select the **Link** component from the left sidebar. 2. From the right sidebar, add a **Reference** field with the following information: | Field | Input | |---|---| | Reference type | Allow multiple models to be referenced | | Model to reference | Blog post, Landing page, Product | | Reference directions | One-way reference | | Relation cardinality | To one | | Display name | Page | | API ID | page | | Field visibility | Read / Write | 3. Click **Add** to save. Your finished Link component should look like this: ![Link component](/images/docs/getting-started/link-component-finished.png) ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 1.2 - Build your content models Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-build-content-models In this lesson, you will create the base content models for the e-commerce project. These models are intentionally incomplete at this stage. References, components, and remote fields are added in later lessons. Every Hygraph project includes two system models: **Asset** and **Query**. These cannot be deleted, but you can add fields to them. The **Asset** model stores images. The **Query** model is where top-level remote fields are configured. You can create models to determine the structure of your content. You can create, rename, edit, and delete them. ## Asset model Before creating models, you need to add two fields to the **Asset** model. Product images require alt text and captions. Both fields are localized, so translated values can be added when Spanish localization is configured in lesson 6.2. 1. In your Hygraph project, click **Schema**, and then under **Models**, click **Asset**. 2. In the right sidebar, click **+Add** next to **Single line text**. Provide the following information, and click **Add** to save: | Field | Input | |---|---| | Display name | Alt text | | API ID | altText | | Description | Add alternative text for the image here | | Localize field | Select checkbox | 3. Add a second `Single line text` field for the caption, and click **Add** to save: | Field | Input | |---|---| | Display name | Caption | | API ID | caption | | Description | Add image caption here | | Localize field | Select checkbox | Your Asset model should look like this: ![Your Asset model](/images/docs/getting-started/asset-model.png) ## Product The `Product` model holds information for product listings. To create the `Product` model, follow these steps: 1. Click **+Add** next to **Models**. 2. Provide the following information, and click **Add Model** to save: | Field | Input | |---|---| | Display name | Product | | API ID | Product | | Plural API ID | Products | | Description | Tutorial project Product model | 3. Add the following fields to the `Product` model: **Single line text** - `Product name`: | Field | Input | |---|---| | Display name | Product name | | API ID | Auto-completed. Leave as is. | | Use as title field | Select checkbox | | Localize field | Select checkbox | | Make field required | Select checkbox | | Set field as unique | Select checkbox | Each API ID is a unique identifier across the project. The system will not allow duplicates. Display names do not have this restriction, but keeping them descriptive helps collaborators navigate the schema. **Slug** - `Product Slug`: | Field | Input | |---|---| | Display name | Product Slug | | API ID | Auto-completed. Leave as is. | | Lowercase | Leave selected | | Make field required | Select checkbox | | Set field as unique | Select checkbox | | Match a specific pattern | Select checkbox, then select `Slug` from the dropdown | | Custom error message | Input value does not match the expected format. | **Asset picker** - `Product image`: | Field | Input | |---|---| | Display name | Product image | | Allow multiple assets | Select checkbox | **Rich Text** - `Product description`: | Field | Input | |---|---| | Display name | Product description | | API ID | Auto-completed. Leave as is. | | Enable embedding | Select checkbox. Select the **Asset** and **Product** models from the dropdown. | | Localize field | Select checkbox | **Enabling embedding on the Product description field** allows editors to embed images and product entries directly in the description body. The Product category model does not exist yet, so you will add it after creating that model. **Float** - `Product price`: | Field | Input | |---|---| | Display name | Product price | | API ID | Auto-completed. Leave as is. | Your Product model should look like this: ![Your Product model so far](/images/docs/getting-started/product-model-initial-fields.png) This model is not finished. A product variant component is added in lesson 4 and a reviews remote field in lesson 5. ## Product category The `Product category` model holds categories that products are assigned to. It connects to the `Product` model through a reference, which we configure in lesson 2. To create the `Product category` model, follow these steps: 1. Click **+Add** next to **Models**. 2. Provide the following information, and click **Add Model** to save: | Field | Input | |---|---| | Display Name | Product category | | API ID | ProductCategory | | Plural API ID | ProductCategories | | Description | Select a product category | 3. Add the following fields to the `Product category` model: **Single line text** - `Category name`: | Field | Input | |---|---| | Display name | Category name | | Use as title field | Select checkbox | | Localize field | Select checkbox | | Make field required | Select checkbox | | Set field as unique | Select checkbox | **Slug** - `Slug`: | Field | Input | |---|---| | Display name | Slug | | Lowercase | Leave selected | | Make field required | Select checkbox | | Set field as unique | Select checkbox | | Match a specific pattern | Select checkbox | | Custom error message | Input value does not match the expected format. | **Rich Text** - `Description`: | Field | Input | |---|---| | Display name | Description | | Localize field | Select checkbox | Your `Product category` model should look like this: ![Your Product category model so far](/images/docs/getting-started/product-category-model-fields.png) Now return to the `Product` model and edit the `Product description` Rich Text field. Add **Product category** to the **Enable embedding** dropdown. ![Product category in Rich Text embeds](/images/docs/getting-started/product-category-rich-text.png) **Schema building is not always linear.** Models are interconnected, and you will sometimes need to return to an earlier model after creating a later one. This is expected. ## Blog post The Blog post model holds articles that promote products. To create the `Blog Post` model, follow these steps: 1. Click **+Add** next to **Models**. 2. Provide the following information, and click **Add Model** to save: | Field | Input | |---|---| | Display Name | Blog Post | | API ID | BlogPost | | Plural API ID | BlogPosts | | Description | Articles to promote our products | 3. Add the following fields to the `Blog Post` model: **Single line text** - `Title`: | Field | Input | |---|---| | Display name | Title | | Use as title field | Select checkbox | | Localize field | Select checkbox | | Make field required | Select checkbox | | Set field as unique | Select checkbox | **Slug** - `Slug`: | Field | Input | |---|---| | Display name | Slug | | Generate slug from template | Select checkbox | | Slug template | `{title}` | | Lowercase | Select checkbox | | Match a specific pattern | Select checkbox, then select `Slug` from the dropdown | | Custom error message | Input value does not match the expected format. | **Rich Text** - `Body`: | Field | Input | |---|---| | Display name | Body | | Localize field | Select checkbox | | Enable embedding | Select checkbox. Select **Blog Post**, **Product**, and **Product category** from the dropdown. | Your Blog post model should look like this: ![Blog post model fields](/images/docs/getting-started/blog-post-model-fields.png) ## Seller information The Seller information model holds business details referenced from the landing page. To create the `Seller information` model, follow these steps: 1. Click **+Add** next to **Models**. 2. Provide the following information, and click **Add Model** to save: | Field | Input | |---|---| | Display Name | Seller information | | API ID | SellerInformation | | Plural API ID | SellerInformations | 3. Add the following fields to the `Seller information` model: **Single line text** - `Business name`: | Field | Input | |---|---| | Display name | Business name | | Use as title field | Select checkbox | | Localize field | Select checkbox | | Make field required | Select checkbox | **Slug** - `Slug`: | Field | Input | |---|---| | Display name | Slug | | Lowercase | Leave selected | | Make field required | Select checkbox | | Set field as unique | Select checkbox | | Match a specific pattern | Select checkbox, then select `Slug` | | Custom error message | Input value does not match the expected format. | **Asset picker** - `Business logo`: | Field | Input | |---|---| | Display name | Business logo | **Rich Text** - `Business description`: | Field | Input | |---|---| | Display name | Business description | | API ID | Auto-completed. Leave as is. | | Localize field | Select checkbox | ## Landing page The Landing page model supports flexible page structures. It is intentionally minimal at this stage. Component fields and references are added in lessons 2 and 4. 1. Click **+Add** next to **Models**. 2. Provide the following information, and click **Add Model** to save: | Field | Input | |---|---| | Display Name | Landing page | | API ID | LandingPage | | Plural API ID | LandingPages | 3. Add the following fields to the `Landing page` model: **Single line text** - `Landing page title`: | Field | Input | |---|---| | Display name | Landing page title | | Use as title field | Select checkbox | | Localize field | Select checkbox | **Slug** - `Link`: | Field | Input | |---|---| | Display name | Link | | API ID | Auto-completed. Leave as is. | | Generate slug from template | Select checkbox | | Slug template | `{landingPageTitle}` | | Lowercase | Leave selected | | Set field as unique | Select checkbox | | Match a specific pattern | Select checkbox. Select **Custom** and enter: `^[a-z0-9\/]+(?:[-\/][a-z0-9]+)*$` | | Custom error message | Input value does not match the expected format. | ## Navigation The Navigation model is included in the cloned project. At this stage it contains the `Nav ID` field, which is a slug field used as the navigation identifier. This model is incomplete. A way to hold navigation links is added in lesson 4.2 after creating the Link component. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 4 - Components Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-components-overview This section covers building the components the e-commerce project needs and attaching them to the correct models. A component is a reusable set of fields defined once in the schema and embedded in models as a basic or modular component field. The components built here solve two specific problems in this project. The `Product Variant` modular component makes it possible for a single `Product` model to handle clothing, shoes, accessories, and decor, each with its own required fields, without creating four separate models. The `Stripes` modular component on the `Landing page` model gives editors the ability to compose pages from a variable combination of CTA and Product Grid sections. By the end of lesson 4.2, the following models are updated: - `Product` — `Product Variant` and `Related Products` components attached - `Landing page` — `Stripes` modular component attached - `Navigation` — `Nav Link` component attached, completing the model left open in lesson 1.2 ## Components and component fields A component and a component field are two different things. You create the component first, then embed it in a model using a component field. Hygraph supports two types of component fields: | Type | What it does | |---|---| | Basic component field | Embeds a single component type. Use this when the field always contains the same structure. | | Modular component field | Allows editors to choose from a set of component types. Use this when editors need to select which component fills the field. | The product type components (`Clothing`, `Shoes`, `Accessories`, `Decor`) use a modular component field inside `Product Variant` because the content editor needs to present a choice. The `Related Products` component uses a basic component field because no choice is required. It always contains the same structure. ## Build order matters Some components depend on others. Build them in this order: 1. Related Products 2. Clothing, Shoes, Accessories, Decor (in any order) 3. Product Variant (depends on 2) 4. Button 5. Call to Action (depends on 4) 6. Product Grid 7. Link component modification (pre-built in the cloned project) For the complete components documentation, see [Components](/docs/developer-guides/schema/components). ## Lessons in this section | Lesson | What you will do | |---|---| | [4.1 Build components](/docs/getting-started/tutorial/tutorial-build-components) | Create components and configure their fields, references, and nested component fields | | [4.2 Add components to your models](/docs/getting-started/tutorial/tutorial-add-components-to-models) | Attach the components to the `Product`, `Landing page`, and `Navigation` models to complete the schema | ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 3.1 - Configure enumerations Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-configure-enumerations In this lesson, you will create enumerations for product size and color values that the product variant components will use. These must exist in the schema before you can build the product variant components in lesson 4. ## Add enumerations All enumerations follow the same process. In the Schema editor, click **+Add** next to **Enumerations** in the left sidebar. Fill in the display name and API ID, then add enumeration values one by one by entering the display name and clicking **+ Add**. Click **Add Enumeration** to save. 1. Go to **Schema**, and click **+Add** next to **Enumerations**. 2. Provide the following values for each enumeration, and click **Add Enumeration** to save. **Clothes size** |Field |Input | |-------------------|-------------------------------------------------| |Display name |Clothes size | |API ID |ClothesSize | |Enumeration values |One by one, add the following: XS, S, M, L, XL | **Shoes size** | Field | Input | |---|---| | Display name | Shoes size | | API ID | ShoesSize | | Enumeration values | Size_35, Size_36, Size_37, Size_38, Size_39, Size_40, Size_41, Size_42, Size_43, Size_44 | **Wearable items color** | Field | Input | |---|---| | Display name | Wearable items color | | API ID | WearableItemsColor | | Enumeration values | Red, Green, Blue, Black, White | **Decor items color** | Field | Input | |---|---| | Display name | Decor items color | | API ID | DecorColor | | Enumeration values | Gold, Silver, Bronze, Cobalt | After adding all enumerations, the left sidebar should look like this: ![Your enumerations listed in the schema](/images/docs/getting-started/enumerations-listed.png) **Why separate enumerations for shoes and clothes sizes?** Shoes and clothing use different size scales. A single "size" enumeration would mix EU shoe sizes with clothing sizes, producing a dropdown that is inconvenient to use in the content editor. Separate enumerations keep each product type's fields meaningful and required. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 2.1 - Configure reference fields Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-configure-reference-fields In this lesson, you will add reference fields to the `Product` and `Landing page` models to connect them to other models in the schema. The reference type, direction, and cardinality configured here determine exactly what you will query later in the API Playground. ## Products and categories Products need to be assignable to multiple categories, and categories need to display all their products. This requires a many-to-many, two-way reference. A two-way reference is required so you can query in both directions: from a product to its categories, and from a category to all its products. 1. Open the **Product** model in the Schema editor and from the right sidebar, add a **Reference** field. 2. Configure the reference field with the following information: **Define relationship** | Field | Input | |---|---| | Reference type | Allow only one model to be referenced | | Model to reference | ProductCategory | | Reference directions | Two-way reference | | Allow multiple Products per ProductCategory | Select checkbox | | Allow multiple ProductCategories per Product | Select checkbox | | Relationship cardinality | The graphic displays that the relationship is of type many-to-many | **Configure reference** | Field | Input | |---|---| | Display name | Pre-configured. Leave as is. | | API ID | Pre-configured. Leave as is. | | Description | Select the categories that apply to your product | | Field visibility | Read / Write | **Configure reverse field** | Field | Input | |---|---| | Display name | Pre-configured. Leave as is. | | API ID | Pre-configured. Leave as is. | | Field visibility | Read / Write | 3. Click **Add** to save. The reference field appears at the bottom of the model. Use the six-dot handle to drag it above the slug field. **What this enables:** In lesson 7, you will be able to query `productCategory(where: { slug: "sportswear" }) { products { productName } }`. The query returns all products within that category. This is possible because of the two-way direction configured here. ## Landing page references The `Landing page` model needs to display featured blog posts, product categories, and seller information. Each of these is a one-way reference. The `Landing page` queries into those models, but those models do not need to query back into `Landing pages`. 1. Open the **Landing page** model in the Schema editor and from the right sidebar under **Relation**, select **Reference**. 2. Configure the reference field for the `Blog post` model with the following information: **Define relationship** | Field | Input | |---|---| | Reference type | Allow only one model to be referenced | | Model to reference | BlogPost | | Reference directions | One-way reference | | Allow multiple BlogPosts per LandingPage | Select checkbox | **Configure reference** | Field | Input | |---|---| | Display name | Pre-configured. Leave as is. | | API ID | Pre-configured. Leave as is. | | Description | Featured item | | Field visibility | Read / Write | 3. Click **Add** to save. 4. Add another **Reference** field from the right sidebar. Configure the reference field for the `Product category` model with the following information: **Define relationship** | Field | Input | |---|---| | Reference type | Allow only one model to be referenced | | Model to reference | ProductCategory | | Reference directions | One-way reference | | Allow multiple ProductCategories per LandingPage | Select checkbox | **Configure reference** | Field | Input | |---|---| | Display name | Pre-configured. Leave as is. | | API ID | Pre-configured. Leave as is. | | Description | Browse our categories | | Field visibility | Read / Write | 5. Click **Add** to save. 6. Add another **Reference** field from the right sidebar. Configure the reference field for the `Seller information` model with the following information: **Define relationship** | Field | Input | |---|---| | Reference type | Allow only one model to be referenced | | Model to reference | SellerInformation | | Reference directions | One-way reference | | Relation cardinality | To one | **Configure reference** | Field | Input | |---|---| | Display name | Pre-configured. Leave as is. | | API ID | Pre-configured. Leave as is. | | Description | Business information | | Field visibility | Read / Write | 7. Click **Add** to save. Your Landing page model should now look like this: ![Your Landing page model so far](/images/docs/getting-started/landing-page-model-with-references.png) **Why one-way for Landing page references, but two-way for Products and categories?** A Blog post, Product category, or Seller information entry has no use case for querying which landing pages reference it. The two-way reference on Products and categories exists because the project needs to navigate from both sides. Where that bidirectional query isn't needed, a one-way reference keeps the schema clean. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 9.1 - Configure webhooks Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-configure-webhooks In this lesson, you will configure a webhook that triggers a new deployment whenever a product entry is published in Hygraph. Without this, publishing content in Hygraph does not update the live storefront and the deployed site continues to show the version built at the last deployment. ## Generate a build hook Before configuring the webhook in Hygraph, generate a build hook URL on your deployment platform. Hygraph will send a POST request to this URL whenever the webhook fires. ### Netlify 1. Go to your site in Netlify and navigate to **Project configuration > Build & deploy > Continuous deployment > Build hooks**. 2. In the **Build hook name** field, enter `Deploy from Hygraph`. 3. In the **Branch to build** dropdown, select `main`. 4. Click **Save**. 5. Copy the generated URL. ### Vercel 1. Go to your project in Vercel and navigate to **Settings > Git > Deploy Hooks**. 2. In the hook name field, enter `Deploy from Hygraph`. 3. In the branch field, enter `main`. 4. Click **Create Hook**. 5. Copy the generated URL. ## Configure the webhook in Hygraph 1. Navigate to **Project Settings > Automation > Webhooks** in your Hygraph project. 2. Click **Add webhook**. 3. Fill in the following information: | Field | Input | |---|---| | Name | Deploy to Storefront | | Description | Trigger published | | Include payload | Enable to send data via the webhook | | Method | POST | | URL | Paste the build hook URL copied from Netlify or Vercel | | Secret key | Generate a strong random string and enter it here. See the note below. | | Headers | Leave blank | **The secret key** is how the receiving endpoint verifies the request came from Hygraph. Without it, any POST request to the build hook URL triggers a deployment. Add a strong secret and store it securely. 4. Under **Triggers**, configure the following: | Field | Input | |---|---| | Content model | Product | | Stage | PUBLISHED | | Actions | Leave empty | | Sources | Leave empty | You need to select the `Product` model because product content is what the storefront displays. Selecting `PUBLISHED` means the webhook only fires when content is published, and saving a content entry does not trigger a deployment. Leaving `Actions` and `Sources` empty acts as a wildcard: all publish actions from all sources trigger the webhook. 5. Click **Add webhook** to save. Publishing any `Product` entry in Hygraph automatically triggers a new storefront deployment. ## Verify the webhook To verify the webhook is working, publish a content entry and confirm a new build starts on your deployment platform. 1. Navigate to **Content** and open any `Product` entry. 2. Modify the product entry, for example, edit the product description. 3. Click **Save & Publish**. 4. Check your deployment platform for a new build. - **Netlify**: Navigate to **Deploys** in your Netlify site and check if a new build appears at the top of the list, triggered by the webhook. - **Vercel**: Navigate to **Deployments** in your Vercel project and check if a new deployment appears, triggered by the webhook. If no build starts, check the following: - The webhook URL matches the build hook URL exactly. There should be no trailing spaces or missing characters. - The content entry you published belongs to the **Product** model. The trigger is scoped to Product only. - The entry moved to the `PUBLISHED` stage. Saving an entry does not trigger the webhook. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 8.2 - Connect the storefront Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-connect-storefront In this lesson, you will configure Content API access in Hygraph and add two environment variables to the starter. By the end, the storefront is running locally and displaying published content. ## Two access modes Before configuring anything, it helps to understand why there are two separate configurations. Hygraph exposes a single Content API endpoint. The starter uses two different ways to access content through that endpoint: - **The Content API** serves the storefront for public visitors. It only returns content in the `PUBLISHED` stage. No authentication is required. - **A Permanent Auth Token (PAT)** grants the frontend access to `DRAFT` content. It is used only for the preview URL configured in lesson 8.3. ## Configure Content API permissions The Public Content API needs read permissions initialized before unauthenticated requests can return content. 1. Navigate to **Project settings > Access > Content API**. 2. In the **Content Permissions** box, click **Initialize defaults**. The content permissions box now looks like this: ![Content permissions initialized](/images/docs/getting-started/public-content-api-permissions.png) 3. Navigate to **Project settings > Access > Endpoints**. Copy the **High Performance Content API** endpoint URL from this screen. You will need it while [adding environment variables](#add-environment-variables). For a full reference on public API permissions, see [Public API permissions](/docs/api-reference/basics/authorization#public-api-permissions). ## Create a PAT for draft content 1. Navigate to **Project settings > Access > Permanent Auth Tokens**. 2. Click **+ Add token**. 3. Enter a name and optional description, select **DRAFT** as the default stage for content delivery, and click **Add & configure permissions**. 4. On the token details screen, copy the token value. You will need it while [adding environment variables](#add-environment-variables). For a full reference on Permanent Auth Tokens, see [Authorization](/docs/api-reference/basics/authorization). ## Add environment variables Copy the `.env.sample` file and rename it to `.env.local`: ```bash cp .env.sample .env.local ``` Open `.env.local` and add the two values collected above: ```bash HYGRAPH_ENDPOINT=YOUR_CONTENT_API_ENDPOINT_HERE HYGRAPH_DEV_AUTH_TOKEN=YOUR_DRAFT_TOKEN_HERE HYGRAPH_PREVIEW_SECRET= ``` Leave `HYGRAPH_PREVIEW_SECRET` empty for now. You will configure it in the next lesson. ## Run the storefront Start the local development server: ```bash npm run dev ``` Open `http://localhost:3000` in your browser. The storefront should display your published content. ![Starter homepage](/images/docs/getting-started/starter-homepage.png) ![Product page](/images/docs/getting-started/product-page.png) The Content API only returns content in the `PUBLISHED` stage. If the storefront is blank, open the content editor and verify that all content entries created in lesson 6.1 are published. The storefront renders your landing pages, product pages, navigation, and review data using the same GraphQL queries practiced in lesson 7.1. The `utils/` directory in the starter contains the query functions. Spend some time exploring the code in your editor to understand how the Hygraph content maps to the frontend components. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 1 - Content models Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-content-models-overview This section covers planning the content structure of the e-commerce project and building it in the Hygraph schema editor. The field names, model relationships, and component structures defined here are what the API exposes and the frontend consumes. Everything configured in later lessons, such as queries, mutations, frontend connection, and webhooks, depends on the schema built here. By the end of lesson 1.2, the project contains the following models with their initial fields: - Product - Product category - Blog post - Seller information - Landing page - Navigation These models are intentionally incomplete at this stage. References are added in lesson 2, components in lesson 4, and remote fields in lesson 5. The schema is built in layers, not all at once. ## Key terms Before building, the following terms appear in the schema editor: ![Project models](/images/docs/getting-started/hygraph-project-models.png) **Schema:** The complete content structure of your project. It contains your models, components, enumerations, and remote sources. **Models:** Containers that define the shape of a content type. A `Product` model defines what a product entry looks like. When an editor creates a product, they fill in the fields that model defines. **Fields:** The individual data points stored on a model. A `Product` model might contain a `name` field (Single line text), a `price` field (Float), and an `image` field (Asset picker). Fields have types, and those types determine what data can be stored and how it can be queried. In GraphQL, field types are called scalars. Hygraph provides scalar types for strings, integers, floats, booleans, dates, colors, geo-coordinates, and more. These appear in the schema editor's right sidebar when adding a field. ## Lessons in this section The following lessons apply content modeling concepts directly to this project. For a deeper understanding of those concepts, read [Content modeling in Hygraph](/docs/core-concepts/content-modeling/content-modeling-in-hygraph). | Lesson | What you will do | |---|---| | [1.1 Design your content models](/docs/getting-started/tutorial/tutorial-design-content-models) | Map the models, components, enumerations, and remote data the project needs before touching the schema editor | | [1.2 Build your content models](/docs/getting-started/tutorial/tutorial-build-content-models) | Create the base models and add their initial fields in the Hygraph schema editor | ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Content Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-content-overview This section covers creating all the content the e-commerce project needs and understanding how the content editor reflects the schema built in earlier lessons. Every field, dropdown, reference, and component you see here was configured in lessons 1 through 5. If a product variant presents only size and color fields for the selected product type, that is the modular component from lesson 4.1 working as intended. If a category reference allows selecting multiple categories per product, that is the many-to-many configuration from lesson 2.1. The content editor is where schema decisions become testable. By the end of lesson 6.3, the project contains: - Published product categories - Core product entries with related products, images, and variants - Seller information entry - Landing pages with `Stripes` components - Navigation entry with links - Localized Spanish content for the Summer Campaign and products - Published content ready to query in the API Playground ## Lessons in this section | Lesson | What you will do | |---|---| | [6.1 Create content](/docs/getting-started/tutorial/tutorial-create-content) | Create product categories, seller information, products, landing pages, and navigation entries | | [6.2 Localize content](/docs/getting-started/tutorial/tutorial-localize-content) | Add a Spanish locale and write localized content for the Summer Campaign and products | | [6.3 Understand content stages](/docs/getting-started/tutorial/tutorial-content-stages) | Learn how DRAFT and PUBLISHED stages affect what the Content API returns and what the frontend displays | ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # 6.3 Understand content stages Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-content-stages Content stages in Hygraph are not just an editorial workflow feature. They determine what the Content API returns and what your frontend displays. Understanding this now prevents the most common source of confusion when connecting the frontend in lesson 8. ## DRAFT and PUBLISHED Hygraph provides two system content stages: `DRAFT` and `PUBLISHED`. Every content entry starts in `DRAFT`. When you click **Save & Publish**, the entry is promoted to `PUBLISHED`. At that point, the entry exists in both stages simultaneously. `DRAFT` always reflects the current state of the entry, and `PUBLISHED` reflects the last published version. When you edit a published entry and click **Save** without publishing, the entry becomes **outdated**. The `DRAFT` stage contains changes that have not yet been promoted to `PUBLISHED`. The published version on the frontend remains unchanged until you publish again. ![Table showing content in stages DRAFT, PUBLISHED, and outdated](/images/docs/getting-started/content-stages-comparison.png) **The API consequence:** Hygraph uses a single Content API endpoint. Which stage you read depends on how access is configured via public permissions, a Permanent Auth Token (PAT), or stage headers and query parameters. Unauthenticated public access with default permissions only returns entries that have been published. If an entry has never been published, those requests return no data for that entry. In lesson 8.2, you will configure a Permanent Auth Token (PAT) that grants the frontend access to draft content for preview purposes. The public storefront uses unauthenticated access configured for the `PUBLISHED` stage. Understanding the distinction now means that when you see different results in the API Playground versus the frontend, you will know why. Hygraph also supports custom content stages. For example, a Review stage between DRAFT and PUBLISHED for editorial workflows that require approval before publishing. See [Content stages](/docs/developer-guides/content/content-stages) for details. ## Save vs Save & Publish Every time you create or edit a content entry, you choose between two actions: - **Save** stores the changes in the `DRAFT` stage only. The published version is not updated. Use this when content needs review before going live. - **Save & Publish** stores the changes in `DRAFT` and promotes them to `PUBLISHED` simultaneously. Use this when content is ready to be consumed by the frontend. ![Save and Save & publish buttons](/images/docs/getting-started/save-publish-options.png) All entries created in lesson 6.1 used **Save & Publish**, which means they exist in both `DRAFT` and `PUBLISHED`. If you used **Save** only at any point, those entries will not appear in responses configured for the `PUBLISHED` stage, including in the connected storefront. If your frontend appears to be missing content after connecting it in lesson 8, check whether the relevant entries have been published. An entry that exists in `DRAFT` only is not visible when querying for the `PUBLISHED` stage. ## Content duplication Hygraph lets you duplicate content entries to save time when creating similar entries. To duplicate an entry, open it in the edit view and click the duplication icon at the top of the screen. The duplicate loads with the same field values as the original, with `(copy)` appended to the title field. If a duplicated entry contains reference fields, some relations are duplicated and others are not. The system notifies you when this is the case. See [Duplicating content](/docs/developer-guides/content/duplicating-content) for details on which relations are preserved. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # 6.1 Create content Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-create-content In this lesson, you will populate the e-commerce project with content. The fields, dropdowns, references, and components in the content editor are a direct result of the schema built in lessons 1 through 5. If anything looks unexpected, it is worth returning to the relevant schema lesson to verify the configuration. The lesson is structured in stages because some content depends on other content existing first. Products cannot have related products until other products exist. Landing pages cannot reference blog posts or categories until those entries are published. Follow the sections in order. ## Assets The cloned project already contains product images. You need to add alt text and a caption to the headband image to get started. 1. In your Hygraph project, click **Assets**. 2. Type `headband` in the search filter. 3. Open the first result to edit the asset. 4. Fill in the following fields and click **Save & Publish**: | Field | Input | |---|---| | Alt text | Cotton headband | | Caption | A soft white cotton headband | 5. Click the back arrow next to **Edit Asset** at the top left to return to the assets table. 6. Click the **X** next to the search filter to reset it. For alt text and caption data for all remaining assets, see [Create content — additional practice](/docs/getting-started/tutorial/tutorial-create-content-additional-practice#assets). Adding this data is optional and does not affect the frontend connection. ## Product categories The `Product category` model was created in lesson 1.2 and connected to the `Product` model through a many-to-many reference in lesson 2.1. Each category entry created here can later be assigned to multiple products, and each product can belong to multiple categories. No product entries exist yet, so you will create the categories first and add product assignments later. 1. Go to **Content**, and under **Default Views**, click **Product category**. 2. Click **+ Add entry**. 3. Create the following entry and click **Save & Publish**: | Field | Input | |---|---| | Category name | Clothes | | Slug | clothes | | Description | You will find clothes here | Repeat the process for each of the following categories: | Category name | Slug | Description | |---|---|---| | Shoes | shoes | You will find shoes here | | Sportswear | sportswear | You will find sportswear here | | Urban | urban | You will find urban-style items here | | New arrival | new-arrival | You will find our latest arrivals here | | Decor | decor | You will find decor items here | | Accessories | accessories | You will find accessories here | Some categories overlap by design. Because the reference between products and categories is many-to-many, one product can belong to both New arrival and Sportswear at the same time. Your Product categories view should now look like this: ![Product categories in the content editor with entries](/images/docs/getting-started/product-category-table-full.png) ## Seller information The Seller information model holds business details that the landing page references. Create a single entry. 1. Go to **Content**, and under **Default Views**, click **Seller information**. 2. Click **+ Add entry**. 3. Fill in the following fields and click **Save & Publish**: | Field | Input | |---|---| | Business name | My business | | Slug | my-business | | Business logo | Click **Add business logo**, select the Hygraph logo from your assets, and click the relation icon in the first column to add it | | Business description | This is a description of my business | Your Seller information view should look like this: ![Seller information content editor view with entry](/images/docs/getting-started/seller-information-table.png) ## Products Product entries are created in two steps. In this step, you will create the basic product listing. Related products are added in the next step, once all product entries exist. 1. Go to **Content**, and under **Default Views**, click **Product**. 2. Click **+ Add entry**. ![Add product content entry](/images/docs/getting-started/add-product-content-entry.png) 3. Create the first entry using the following information: | Field | Input | |---|---| | Product name | Black leather shoes | | Product slug | black-leather-shoes | | Product category | Click **Add existing Product categories** and select **Shoes** and **New arrival** | | Product image | Click **Add Product images**, type `black leather shoes` in the search filter, and click **Add selected images** | | Product description | These black leather shoes seamlessly blend sophistication with durability, making them a versatile choice for both formal occasions and everyday wear. The sleek design and high-quality leather ensure a timeless appeal that complements any outfit. | | Product variant | Click **Add component**, select **Shoes**, then set Size to `Size_40` and Color to `Black` | | Product price | 170 | `Product variant` is the modular component field built in lesson 4.1. Clicking **Add component** presents the four product type options — `Clothing`, `Shoes`, `Accessories`, `Decor`. Selecting `Shoes` reveals only the shoe size and color fields, not the clothing size fields. This is the modular component working as configured. 4. Click **Save & Publish**. ![Product content entry](/images/docs/getting-started/product-content-entry.png) Now create the remaining product entries using the following information: **Blue running shoes** | Field | Input | |---|---| | Product name | Blue running shoes | | Product slug | blue-running-shoes | | Product category | Select **Sportswear** and **Shoes** | | Product image | Select images with file name **blue running shoes** | | Product description | These blue running shoes offer both form and function, providing exceptional support and style for your active pursuits. The breathable material and cushioned sole ensure a comfortable experience mile after mile. | | Product variant | Select **Shoes**, then Size `Size_42` and Color `Blue` | | Product price | 130 | **Plaid shirt** | Field | Input | |---|---| | Product name | Plaid shirt | | Product slug | plaid-shirt | | Product category | Select **New arrival**, **Urban**, and **Clothes** | | Product image | Select images with file name **blue plaid shirt** | | Product description | This plaid shirt exudes a timeless charm, perfect for a casual day out or a relaxed evening gathering. The classic checkered pattern and comfortable fit make it a wardrobe staple for effortless style. | | Product variant | Select **Clothing**, then Size `XL` and Color `Blue` | | Product price | 60 | **Necklace** | Field | Input | |---|---| | Product name | Necklace | | Product slug | necklace | | Product category | Select **Accessories** | | Product image | Select images with file name **necklace** | | Product description | This white necklace is crafted from parts of seashells, evoking a relaxed, beachy vibe. Perfect for those looking to add a touch of the sea to their daily style. | | Product variant | Select **Accessories**, then Color `White` | | Product price | 12 | **Headband** | Field | Input | |---|---| | Product name | Headband | | Product slug | headband | | Product category | Select **Accessories** | | Product image | Select images with file name **headband** | | Product description | This white cotton headband provides an elegant and sophisticated touch to your hairstyle. Perfect for completing your look with a blend of fashion and comfort. | | Product variant | Select **Accessories**, then Color `White` | | Product price | 9 | For adding more product entries, see [Create content — additional practice](/docs/getting-started/tutorial/tutorial-create-content-additional-practice#products). Adding these is optional but some API Playground query exercises in lesson 7.1 reference them. ## Related products Now that you've created all product entries, you can add related products to each one. 1. Open the **Headband** entry to edit it. 2. Scroll to the **Related Products** component and click **+ Add Related Products**. The **Title** field is read-only and displays `Related Products`. This is because you set the field to read-only with an initial value when building the component in lesson 4.1. So, every instance of this component shows the same heading. 3. Click **Add existing products** and select: black leather shoes, necklace, blue running shoes, and plaid shirt. 4. Click **Add selected products**, then click **Save & Publish**. ![Component with related products](/images/docs/getting-started/related-products-component.png) Repeat for the remaining product entries: | Product entry | Related products | |---|---| | Blue running shoes | black leather shoes, necklace, headband, plaid shirt | | Black leather shoes | blue running shoes, necklace, headband, plaid shirt | | Necklace | black leather shoes, blue running shoes, headband, plaid shirt | | Plaid shirt | black leather shoes, necklace, headband, blue running shoes | For related product assignments for the additional practice entries, see [Create content — additional practice](/docs/getting-started/tutorial/tutorial-create-content-additional-practice#related-products). ## Blog post Create a blog post entry to use on the landing page. 1. Go to **Content**, and under **Default Views**, click **Blog post**. 2. Click **+ Add entry** and fill in the following: | Field | Input | |---|---| | Title | Our new leather shoes | | Slug | Auto-completes from the title. Leave as is. | | Body | Type `Take a look at this awesome new arrival`. Then click **Embed**, select **Block**, choose the **Product** model from the dropdown, click **Select model**, and select the **Black leather shoes** entry. | 3. Click **Save & Publish**. Your blog post entry should look like this: ![Blog post complete entry](/images/docs/getting-started/blog-post-entry.png) ## Landing pages You will create two landing pages: a homepage and a Summer Campaign page. The homepage could not have been created earlier because it references seller information, blog posts, and products that needed to exist first. ### Homepage 1. Go to **Content**, and under **Default Views**, click **Landing page**. 2. Click **+ Add entry** and fill in the following: | Field | Input | |---|---| | Landing page title | Home | | Link | `/` | | Blog posts | Leave empty for now | | Product categories | Leave empty for now | | Seller information | Add the seller information entry created earlier | | Stripes | Click **+ Add component** and add a `Call to Action` and a `Product Grid` using the information below | **Call to Action:** | Field | Input | |---|---| | Heading | Main Headline for the page | | Body | We provide amazing products from outerwear, shoes, home goods, and more! Be sure to check out all the amazing products. | | Image | Add the Hygraph Logo asset | | Button | Click **+ Add Button**, enter `Shop Now` in the Text field and `https://google.com` in the URL field | **Product Grid:** | Field | Input | |---|---| | Headline | Picks of the month | | Products | Add relations to: blue running shoes, black leather shoes, necklace, headband, plaid shirt | 3. Click **Save & Publish**. Your homepage entry should look like this: ### Summer Campaign 1. Go to **Content**, and under **Default Views**, click **Landing page**. 2. Click **+ Add entry** and fill in the following: | Field | Input | |---|---| | Landing page title | Summer Campaign | | Link | summer-campaign | | Blog posts | Leave empty for now | | Product categories | Leave empty for now | | Seller information | Add the seller information entry created earlier | | Stripes | Click **+ Add component** and add a `Call to Action` and a `Product Grid` using the information below | **Call to Action:** | Field | Input | |---|---| | Heading | Get ready for summer with these amazing deals | | Body | The Summer Sale is in full swing! See the amazing summer deals we have listed below! | | Image | Leave empty | | Button | Leave empty | **Product Grid:** | Field | Input | |---|---| | Headline | Summer wear | | Products | Add relations to: blue running shoes, black leather shoes, necklace, headband, plaid shirt | 3. Click **Save & Publish**. ## Navigation The `Navigation` model uses the `Link` component built in lesson 4.1. Each `Nav Link` entry in the navigation maps to one link in the frontend navigation bar. 1. Go to **Content**, and under **Default Views**, click **Navigation**. 2. Click **+ Add entry** and fill in the following: | Field | Input | |---|---| | Nav ID | main | 3. Click **+ Add Link** to add the first Nav Link component and fill in: | Field | Input | |---|---| | Display Text | Clothes | | Page | Leave empty | | External URL | `/category/clothes` | 4. Click **+ Add another Link** and repeat for each of the following: **Shoes** | Field | Input | |---|---| | Display Text | Shoes | | Page | Leave empty | | External URL | `/category/shoes` | **Accessories** | Field | Input | |---|---| | Display Text | Accessories | | Page | Leave empty | | External URL | `/category/accessories` | **Decor** | Field | Input | |---|---| | Display Text | Decor | | Page | Leave empty | | External URL | `/category/decor` | **Summer Campaign** | Field | Input | |---|---| | Display Text | Summer Campaign | | Page | Click **Add existing document** and select the Summer Campaign landing page | | External URL | Leave empty | 5. Click **Save & Publish**. The navigation entry now contains all the links the frontend needs. These will be visible when the storefront is connected in lesson 8. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Content creation — additional practice Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-create-content-additional-practice This page contains optional additional content for lesson 6.1. None of this is required for the frontend to connect and function. Some of the additional product entries are referenced in more advanced API Playground exercises in lesson 7.1. Content on this page depends on other content existing first. You cannot localize an alt text field that was never filled in. You cannot add related products that were never created. ## Assets Add alt text and captions to the following assets using the same process as in lesson 6.1: | Asset | Alt text | Caption | |---|---|---| | Green hoodie | Green hoodie | A comfortable green hoodie, 100% cotton | | Blue running shoes | Blue running shoes | A pair of lightweight blue running shoes | | Red urban shoes | Red urban shoes | A pair of stylish and modern red urban shoes | | Blue plaid shirt | Blue plaid shirt | A classic and warm blue plaid shirt | | Black leather shoes | Black leather shoes | A pair of elegant black leather shoes | | Coffee table | Coffee table | Coffee table with glass top and metal legs | | Coffee tray | Coffee tray | Metal coffee tray for two cups | | Floor lamp | Floor lamp | Floor lamp with paper top and bronze details | | Vase | Vase | Small metal vase | | Desk lamp | Desk lamp | An elegant silver lamp | | Bag | Green bag | A modern green leather bag | | Necklace | White necklace | A lovely white necklace with summer vibes | | Wallet | Black leather wallet | A black leather wallet with space for all your cards | | Fanny pack | Red fanny pack | A modern red fanny pack to carry your essentials | | Headband | Cotton headband | A soft white cotton headband | [Return to lesson 6.1 — Create content](/docs/getting-started/tutorial/tutorial-create-content#assets) ## Products Create the following additional product entries using the same process as in lesson 6.1. **Green Hoodie** | Field | Input | |---|---| | Product name | Green Hoodie | | Product slug | green-hoodie | | Product category | Select **Clothes**, **Sportswear**, and **New arrival** | | Product image | Select images with file name **green hoodie** | | Product description | This green hoodie combines comfort and style seamlessly, making it your go-to choice for a casual yet trendy look. Its soft fabric and versatile shade of green make it a wardrobe essential for all seasons. | | Product variant | Select **Clothing**, then Size `L` and Color `Green` | | Product price | 45 | **Desk lamp** | Field | Input | |---|---| | Product name | Desk lamp | | Product slug | desk-lamp | | Product category | Select **Decor** | | Product image | Select images with file name **desk lamp** | | Product description | This silver desk lamp illuminates your workspace with elegance and style. Its modern design and sleek silver finish make it a standout piece for your desk. | | Product variant | Select **Decor**, then Color `Silver` | | Product price | 35 | **Wallet** | Field | Input | |---|---| | Product name | Wallet | | Product slug | wallet | | Product category | Select **Accessories** | | Product image | Select images with file name **wallet** | | Product description | This black leather wallet combines functionality and style in a modern, compact design. With ample space for your cards and cash, it's the perfect accessory for carrying your essentials with elegance. | | Product variant | Select **Accessories**, then Color `Black` | | Product price | 39 | **Urban shoes** | Field | Input | |---|---| | Product name | Urban shoes | | Product slug | urban-shoes | | Product category | Select **Shoes** and **Urban** | | Product image | Select images with file name **red urban shoes** | | Product description | These red urban shoes effortlessly blend fashion with comfort, making a bold statement in any cityscape. The sleek design and cushioned insole ensure both style and ease for your urban adventures. | | Product variant | Select **Shoes**, then Size `Size_38` and Color `Red` | | Product price | 130 | **Colorful socks** | Field | Input | |---|---| | Product name | Colorful socks | | Product slug | colorful-socks | | Product category | Select **Clothes**, **Urban**, **Accessories**, and **New arrival** | | Product image | Select images with file name **colorful socks** | | Product description | These vibrant socks are designed to add a touch of joy to your everyday style. With eye-catching colors and a comfortable fit, they're the perfect choice to express your personality with every step. | | Product variant | Select **Accessories**, then Color `Red` | | Product price | 12 | **Floor lamp** | Field | Input | |---|---| | Product name | Floor lamp | | Product slug | floor-lamp | | Product category | Select **Decor** | | Product image | Select images with file name **floor lamp** | | Product description | This floor lamp seamlessly blends the warmth of paper with metal and wooden details, adding a modern and elegant touch to your space. Its unique design softly and harmoniously lights up your surroundings. | | Product variant | Select **Decor**, then Color `Bronze` | | Product price | 240 | **Coffee table** | Field | Input | |---|---| | Product name | Coffee table | | Product slug | coffee-table | | Product category | Select **Decor** | | Product image | Select images with file name **coffee table** | | Product description | This coffee table blends elegance and modernity with its glass surface and metal legs. Perfect to add a contemporary touch to your living space. | | Product variant | Select **Decor**, then Color `Silver` | | Product price | 199 | **Coffee tray** | Field | Input | |---|---| | Product name | Coffee tray | | Product slug | coffee-tray | | Product category | Select **Decor** | | Product image | Select images with file name **coffee tray** | | Product description | This metal coffee tray is crafted for two cups, adding a touch of industrial style to your coffee experience. Its sleek and durable design makes it a perfect addition to your morning routine. | | Product variant | Select **Decor**, then Color `Silver` | | Product price | 19 | **Vase** | Field | Input | |---|---| | Product name | Vase | | Product slug | vase | | Product category | Select **Decor** | | Product image | Select images with file name **vase** | | Product description | This small metal vase is versatile and stylish, perfect for displaying fresh flowers or storing bathroom items like makeup brushes. Its modern design easily complements any space. | | Product variant | Select **Decor**, then Color `Silver` | | Product price | 15 | **Bag** | Field | Input | |---|---| | Product name | Bag | | Product slug | bag | | Product category | Select **Accessories** | | Product image | Select images with file name **bag** | | Product description | This green leather bag is the perfect accessory to carry your belongings with style and elegance. Crafted from high-quality leather, its spacious and modern design is perfect for any occasion. | | Product variant | Select **Accessories**, then Color `Green` | | Product price | 52 | **Fanny pack** | Field | Input | |---|---| | Product name | Fanny pack | | Product slug | fanny-pack | | Product category | Select **Accessories** | | Product image | Select images with file name **fanny pack** | | Product description | This red fanny pack is the perfect accessory to carry your essentials comfortably and in style. Its vibrant color and modern design make it the ideal choice for your daily adventures. | | Product variant | Select **Accessories**, then Color `Red` | | Product price | 14 | [Return to lesson 6.1 — Create content](/docs/getting-started/tutorial/tutorial-create-content#products) ## Related products Add related product assignments to the following additional entries: | Product entry | Related products | |---|---| | Green Hoodie | colorful socks, blue running shoes, urban shoes, plaid shirt | | Desk lamp | floor lamp, coffee table, coffee tray, vase | | Wallet | bag, necklace, headband, fanny pack | | Urban shoes | colorful socks, blue running shoes, plaid shirt, black leather shoes | | Floor lamp | coffee table, coffee tray, vase, desk lamp | | Coffee table | floor lamp, coffee tray, vase, desk lamp | | Coffee tray | floor lamp, coffee table, vase, desk lamp | | Vase | floor lamp, coffee table, coffee tray, desk lamp | | Bag | wallet, necklace, headband, fanny pack | | Fanny pack | wallet, bag, necklace, headband | [Return to lesson 6.1 — Create content](/docs/getting-started/tutorial/tutorial-create-content#related-products) --- # 1.1 Design your content models Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-design-content-models In this lesson, you will map the content structure the project requires before building anything in the schema editor. This lesson has no steps to complete in Hygraph. The decisions made here determine every field, reference, and component configured in the lessons that follow. Read [Content modeling in Hygraph](/docs/core-concepts/content-modeling/content-modeling-in-hygraph) to understand the underlying concepts first. ## The project The e-commerce project sells wearables and home goods. Before opening the schema editor, you need to map the content structure against what the store must do. ![Content modeling](/images/docs/getting-started/content-modeling-matters.png) The store has four goals: - **Display product listings with enough detail for a buyer to make a decision**: image, size, color, price, description, and reviews. - **Organize products into categories**, where one product can belong to multiple categories and one category can contain multiple products. - **Display related products on each product page** to encourage further exploration. - **Support a landing page, a blog, seller information, and a navigation structure**. Reviews come from an external source. You will not store them in Hygraph. Instead, you will fetch them from a remote API using Content Federation. ## Proposed content flow Based on those goals, here is what the schema will contain. ![Project structure](/images/docs/getting-started/hygraph-project-structure.png) **Models** | Model | Purpose | |---|---| | `Product` | Product listings with name, slug, images, description, price, and variant | | `Product category` | Categories that products can be assigned to | | `Blog post` | Articles promoting products | | `Seller information` | Business details referenced from the landing page | | `Landing page` | Flexible pages built from component sections | | `Navigation` | Site navigation built from Link components | **Components** | Component | Purpose | |---|---| | Product Variant | Modular component for product type selection (Clothing, Shoes, Accessories, or Decor) | | Clothing | Size and color fields for clothing items | | Shoes | Size and color fields for footwear | | Accessories | Color field for accessories | | Decor | Color field for decor items | | Related products | A set of product references for related product sections | | Call to Action | Heading, body, image, and button for CTA sections | | Button | Text and URL for use inside CTA components | | Product Grid | Headline, description, and product references for grid sections | | Link | Display text, URL, and page reference for navigation links | **Product Variant as a modular component, not separate models.** The store sells clothing, shoes, accessories, and decor. Each product type requires different fields. Shoes need a shoe size, clothing needs a clothing size, accessories need neither. Rather than creating four separate product models, the schema uses a single Product model with a modular component field. The component presents only the relevant fields based on the product type selected in the content editor. **Enumerations** | Enumeration | Values | |---|---| | Clothes size | XS, S, M, L, XL | | Shoes size | Size_35 through Size_44 | | Wearable items color | Red, Green, Blue, Black, White | | Decor items color | Gold, Silver, Bronze, Cobalt | **Remote source** | Source | Purpose | |---|---| | HyDemoAPI | Fetches product reviews from an external REST API. Configured as a Remote Field on the Product model and a Top-level Remote Field on the Query model. | **Reviews as a remote field, not a model.** Reviews exist in a third-party system. Migrating them into Hygraph would duplicate data and create a synchronization problem. A remote source connects to the origin directly. Review data appears in the API response alongside Hygraph content, with no migration required. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 3 - Enumerations Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-enumerations-overview This section covers creating the enumerations the product variant components depend on. An enumeration defines a fixed set of allowed values at the schema level. The enumerations configured here, `Clothes size`, `Shoes size`, `Wearable items color`, and `Decor items color`, power the size and color dropdowns in the content editor in later lessons. They need to exist in the schema before the components that use them can be built. ## How enumerations work An enumeration defines a fixed set of allowed values for a field. When a field is typed to an enumeration, the API enforces the allowed values at the schema level. A product entry cannot be published with a color value of "navy" if the enumeration only contains Red, Green, Blue, Black, and White. This is different from a free-text field, where any value is accepted, and different from a reference, where values are editor-managed content entries. Use an enumeration when the set of valid values is fixed, controlled by the schema owner, and unlikely to be extended by editors. [Learn more about enumerations](/docs/developer-guides/schema/using-enumerations). Use a reference when the list of values needs to be managed as content entries by editors. Use a taxonomy when the values are hierarchical. Enumerations are for flat, schema-controlled value sets that change infrequently. ## Lessons in this section | Lesson | What you will do | |---|---| | [3.1 Configure enumerations](/docs/getting-started/tutorial/tutorial-configure-enumerations) | Create enumerations for product size and color values that the product variant components will use | ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 8 - Frontend connection Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-frontend-overview This section covers setting up the Next.js e-commerce starter, connecting it to your Hygraph project, and configuring a preview URL for draft content. The work in this section is configuration only. The starter handles all the frontend code for routing, components, queries, and styling. You need to provide the environment variables that tell the starter where to find your Hygraph project and how to authenticate. The starter uses two different ways to access your Hygraph content: - **The Content API** serves public visitors. It only returns content that has been explicitly published. - **A Permanent Auth Token (PAT)** grants the frontend access to draft content for preview purposes. ## Lessons in this section | Lesson | What you will do | |---|---| | [8.1 Set up the frontend starter](/docs/getting-started/tutorial/tutorial-frontend-setup) | Clone the Next.js e-commerce starter, install dependencies, and orient yourself to the repo structure | | [8.2 Connect your storefront](/docs/getting-started/tutorial/tutorial-connect-storefront) | Configure Content API permissions, create a PAT, and add the environment variables that connect the starter to your Hygraph project | | [8.3 Configure a preview URL](/docs/getting-started/tutorial/tutorial-preview-url) | Add a preview button to the Product model content editor sidebar so you can preview draft product pages before publishing | ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 8.1 - Set up the frontend starter Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-frontend-setup In this lesson, you will clone the Hygraph Next.js e-commerce starter and install its dependencies. By the end, the starter will be running locally and ready to be connected to your Hygraph project in the next lesson. This lesson clones a pre-built starter. If you want to understand how to create a Next.js project from scratch, see the Next.js documentation. Creating a Next.js app from scratch is out of scope for this tutorial. ## Clone the starter 1. Open your terminal and navigate to the directory where you want the project. 2. Run the following command to clone the starter: ```bash git clone https://github.com/hygraph/hygraph-next-commerce-starter.git ``` 3. Navigate into the project directory: ```bash cd hygraph-next-commerce-starter ``` 4. Install the package dependencies: ```bash npm install ``` Your project file tree should look like this: ![Next file tree](/images/docs/getting-started/next-file-tree.png) ## What's in the starter The starter is a Next.js 13 App Router project with Tailwind CSS. Three directories contain the code that powers the storefront: - **`app/`**: Next.js page components and dynamic routes. The product page at `app/products/[slug]/page.js` and the landing page at `app/[slug]/page.js` are the two routes your Hygraph content populates. - **`utils/`**: GraphQL query functions. The queries you wrote in lesson 7.1 are used here to fetch content from Hygraph. Each query function maps to a page or component in the `app/` directory. - **`components/`**: UI components for navigation, product grids, CTAs, landing page sections, and product reviews. ## What's in `.env.sample` The starter includes a `.env.sample` file in the project root. It contains the three environment variable placeholders you will populate in lessons 8.2 and 8.3: ```bash HYGRAPH_ENDPOINT= HYGRAPH_DEV_AUTH_TOKEN= HYGRAPH_PREVIEW_SECRET= ``` Do not populate these yet. Lesson 8.2 explains what each variable controls and where to find the values. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 6.2 - Localize content Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-localize-content In this lesson, you will add a Spanish locale to the project and write localized content for the Summer Campaign and the product entries. While you were building the schema in lesson 1.2, certain fields were marked with the **Localize field** checkbox. Only those fields are available for localization in the content editor. Fields that were not marked are not localizable and display only the default English value. Adding a locale at the project level is what makes the language toggle available at the entry level. Without this step, the Spanish tab does not appear in the content editor. ## Add a locale 1. Navigate to **Project settings > General > Locales**. 2. Use the dropdown to select **Spanish**. 3. Click **Add**. The Spanish locale is now added to the project and the language toggle appears in the content editor for all localizable fields. ## Localized content ### Summer Campaign 1. Open the **Summer Campaign** landing page entry in the content editor. 2. Under **Localizations**, click **+** next to **Spanish** to add fields for the Spanish locale. 3. Fill in the following localized fields and click **Save & Publish**: | Field | Translated content | |---|---| | Landing page title | Campaña de verano | | Stripes > Call to Action > Heading | Prepárate para el verano con estas increíbles ofertas | | Stripes > Call to Action > Body | ¡Las rebajas de verano están en pleno apogeo! Mira las increíbles ofertas de verano que tenemos a continuación! | | Stripes > Product Grid > Headline | Ropa de verano | ### Products Repeat the same process for the following product entries: **Blue running shoes** | Field | Translated content | |---|---| | Product name | Zapatillas para correr azules | | Product description | Estas zapatillas de running azules ofrecen tanto forma como función, brindando un apoyo excepcional y estilo para tus actividades deportivas. El material transpirable y la suela acolchada garantizan una experiencia cómoda kilómetro tras kilómetro. | **Plaid shirt** | Field | Translated content | |---|---| | Product name | Camisa a cuadros | | Product description | Esta camisa a cuadros emana un encanto atemporal, ideal para un día casual fuera o una reunión relajada por la tarde. El patrón clásico a cuadros y el ajuste cómodo la convierten en una prenda básica para un estilo sin esfuerzo. | **Black leather shoes** | Field | Translated content | |---|---| | Product name | Zapatos de cuero negro | | Product description | Estos zapatos de cuero negro combinan de manera impecable la sofisticación con la durabilidad, convirtiéndolos en una elección versátil tanto para ocasiones formales como para uso diario. El diseño elegante y el cuero de alta calidad garantizan un atractivo atemporal que complementa cualquier conjunto. | **Necklace** | Field | Translated content | |---|---| | Product name | Collar | | Product description | Este collar blanco está elaborado con partes de caracoles de mar, evocando la esencia relajada y playera. Perfecto para quienes buscan un toque marino en su estilo diario. | **Headband** | Field | Translated content | |---|---| | Product name | Vincha | | Product description | Esta vincha de algodón blanco brinda un toque elegante y sofisticado a tu peinado. Ideal para completar tu look con un toque de moda y comodidad. | ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Full Tutorial - Build Your First eCommerce Project Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-overview This tutorial takes you through a complete Hygraph project: an e-commerce store selling wearables and home goods. By the end, you will have a working schema, real content, a queryable API, and a connected Next.js storefront. ![Getting started project preview](/images/docs/getting-started/project-preview.png) Every decision in this tutorial is one you will face on a real project. The schema choices you make in lessons 1 through 5 determine what you can query in lesson 7 and what your frontend renders in lesson 8. ## Choose your path Your starting point is a cloned Hygraph project. You can choose your own path through the tutorial. **Option 1: Build from scratch** This clone includes navigation structure and image assets. You will build the schema, content, API configuration, and frontend connection yourself, step by step. Choose this path if you want to understand how every part of a Hygraph project is constructed and why. **Requirements** - Hygraph account - Basic GraphQL knowledge - Basic understanding of [content modeling](/docs/core-concepts/content-modeling/content-modeling-overview) - Code editor, such as VS Code - Current version of Node.js - Netlify or Vercel account (required for lessons 8 and 9) - Growth plan or higher, or a [30-day trial](/docs/getting-started/update-billing), for lessons 5.1 through 5.3 **Option 2: Explore a complete project** This clone includes the complete Hygraph project: all models, components, enumerations, content entries, and localized content already built. You will skip straight to querying and frontend connection. Choose this path if you want to practice API queries, mutations, and frontend integration without building the schema yourself. **Requirements** - Hygraph account - Basic GraphQL knowledge - Basic understanding of [content modeling](/docs/core-concepts/content-modeling/content-modeling-overview) - Growth plan or higher, or a [30-day trial](/docs/getting-started/update-billing), for remote sources ## Clone the project The cloning process is the same for both options. ![Clone project screen](/images/docs/getting-started/clone-project-screen.png) The project already has a name, but you can give it a new name. You can also optionally add a description, select a region, and click **Clone now**. Cloning takes a couple of minutes. When it finishes, you land on your project homepage. ## What's already in your project This section is for Option 2 readers only. If you chose Option 1, move on to the lesson overview below. Your cloned project is fully built. Here is what it contains. **Schema** | Type | What's included | |---|---| | Models | Product, Product category, Blog post, Seller information, Landing page, Navigation | | Components | Related Products, Product variant, Clothing, Shoes, Accessories, Decor, Button, Call to Action, Product Grid, Link | | Enumerations | Clothes size, Shoes size, Wearable items color, Decor items color | | Remote source | HyDemoAPI, a Hygraph-maintained REST API used to fetch product reviews | | Remote fields | Reviews field on the Product model; Reviews top-level field on the Query model | **Content** | Type | What's included | |---|---| | Products | 9 published entries with images, variants, related products, and category assignments | | Product categories | 7 published entries | | Landing pages | Homepage and Summer Campaign, both with localized Spanish content | | Navigation | Main navigation with category and campaign links | | Seller information | 1 published entry | | Assets | All product images with alt text and captions | Your project does not include API tokens, environment variable configuration, a connected frontend, or webhooks. You will set those up in lessons 8 and 9. **Your path through the tutorial** 1. Query your content in the API Playground. 2. Run mutations. 3. Set up the Next.js frontend starter. 4. Connect Hygraph to your local frontend. 5. Configure a preview URL for draft content. 6. Set up a webhook to trigger frontend deploys on publish. ## Lesson overview The full lesson sequence is below. Option 2 readers start at [lesson 7.1](/docs/getting-started/tutorial/tutorial-write-queries). ### Lesson 1 — Content models | # | Lesson | What you will be able to do | |---|---|---| | 1.1 | [Design your content models](/docs/getting-started/tutorial/tutorial-design-content-models) | Sketch your model structure and understand how fields, models, and schema relate to each other | | 1.2 | [Build your content models](/docs/getting-started/tutorial/tutorial-build-content-models) | Create your base models and fields in the Hygraph schema editor | ### Lesson 2 — References | # | Lesson | What you will be able to do | |---|---|---| | 2.1 | [Configure reference fields](/docs/getting-started/tutorial/tutorial-configure-reference-fields) | Connect models to each other using one-to-one, one-to-many, and many-to-many references | ### Lesson 3 — Enumerations | # | Lesson | What you will be able to do | |---|---|---| | 3.1 | [Configure enumerations](/docs/getting-started/tutorial/tutorial-configure-enumerations) | Create predefined value sets that appear as dropdowns in the content editor | ### Lesson 4 — Components | # | Lesson | What you will be able to do | |---|---|---| | 4.1 | [Build components](/docs/getting-started/tutorial/tutorial-build-components) | Create reusable field sets for product variants, CTAs, related products, and navigation links | | 4.2 | [Add components to your models](/docs/getting-started/tutorial/tutorial-add-components-to-models) | Attach your components to models as basic and modular component fields | ### Lesson 5 — Remote Sources | # | Lesson | What you will be able to do | |---|---|---| | 5.1 | [Add a Remote Source](/docs/getting-started/tutorial/tutorial-add-remote-source) | Connect an external REST API to your Hygraph schema | | 5.2 | [Remote Fields](/docs/getting-started/tutorial/tutorial-add-remote-fields) | Fetch remote data within the context of a specific model entry | | 5.3 | [Top-level Remote Fields](/docs/getting-started/tutorial/tutorial-add-top-level-remote-fields) | Fetch remote data outside the context of any model and serve it alongside Hygraph content in a single API call | ### Lesson 6 — The Content Editor | # | Lesson | What you will be able to do | |---|---|---| | 6.1 | [Create content](/docs/getting-started/tutorial/tutorial-create-content) | Create and publish products, categories, landing pages, and navigation entries | | 6.2 | [Localize content](/docs/getting-started/tutorial/tutorial-localize-content) | Add a locale and write localized content for selected fields | | 6.3 | [Understand content stages](/docs/getting-started/tutorial/tutorial-content-stages) | Learn how `DRAFT` and `PUBLISHED` content stages affect what the Content API returns and what the frontend displays | ### Lesson 7 — The API Playground | # | Lesson | What you will be able to do | |---|---|---| | 7.1 | [Exercises: Queries](/docs/getting-started/tutorial/tutorial-write-queries) | Write queries for models, references, components, and remote fields | | 7.2 | [Exercises: Mutations](/docs/getting-started/tutorial/tutorial-write-mutations) | Create, update, publish, and delete content entries programmatically | ### Lesson 8 — Frontend Connection | # | Lesson | What you will be able to do | |---|---|---| | 8.1 | [Set up the frontend starter](/docs/getting-started/tutorial/tutorial-frontend-setup) | Clone and configure the Next.js e-commerce starter locally | | 8.2 | [Connect your storefront](/docs/getting-started/tutorial/tutorial-connect-storefront) | Configure API access permissions, create a PAT, and connect Hygraph to your local frontend | | 8.3 | [Preview URL](/docs/getting-started/tutorial/tutorial-preview-url) | Add a preview button to the content editor sidebar to preview draft content before publishing | ### Lesson 9 — Webhooks | # | Lesson | What you will be able to do | |---|---|---| | 9.1 | [Configure webhooks](/docs/getting-started/tutorial/tutorial-configure-webhooks) | Set up a webhook that triggers a frontend rebuild whenever content is published | ## What's next OR --- # Lesson 8.3 - Configure a preview URL Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-preview-url In this lesson, you will configure a preview URL for the `Product` model. Once configured, every product entry in the content editor displays an **Open live preview** button in its sidebar. Clicking it opens a preview of that product page in your local frontend using the draft content token configured in lesson 8.2. The preview URL uses a secret key to prevent unauthorized access to draft content. Only requests that include the correct secret can trigger a draft preview. Generate a strong secret and do not commit it to version control. ## Configure the preview URL 1. Navigate to the **Schema** and select the **Product** model. 2. Click the **Sidebar** tab. 3. Select the **Preview** widget. 4. Provide the following details: - **Preview Name**: Product preview - **URL template**: `http://localhost:3000/api/draft?slug={productSlug}&model=products&secret=YOUR_SECRET_HERE` `{productSlug}` is handlebars notation. Hygraph replaces it with the `productSlug` field value of the entry being previewed. The API ID `productSlug` was set when you created the Product Slug field in lesson 1.2. 5. Click **Save**. ## Add the preview secret 1. Generate a secret key using a key generator of your choice. Use a strong random string. 2. Replace `YOUR_SECRET_HERE` in the URL template with the generated secret. 3. Open `.env.local` and add the secret as `HYGRAPH_PREVIEW_SECRET`: ```bash HYGRAPH_PREVIEW_SECRET=YOUR_SECRET_HERE ``` 4. Restart the local development server to load the new environment variable: ```bash npm run dev ``` ## Your complete `.env.local` At this point, all three environment variables should be populated. Your `.env.local` file should look like this: ```bash HYGRAPH_ENDPOINT=YOUR_CONTENT_API_ENDPOINT_HERE HYGRAPH_DEV_AUTH_TOKEN=YOUR_DRAFT_TOKEN_HERE HYGRAPH_PREVIEW_SECRET=YOUR_SECRET_HERE ``` If any of the three are missing or incorrect, the preview will not work. ## Verify the preview URL 1. Navigate to the **Content editor** and open any product entry. 2. Click **Open live preview**. The product page should open in a new browser tab at `http://localhost:3000` showing the draft version of that product. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 7 - Queries and mutations Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-queries-mutations-overview This section covers querying and mutating content in the Hygraph API Playground. The API Playground is not a demo environment. It queries the same Content API your frontend will use in lesson 8. Every query you run here returns real data from your project, and every mutation makes a real change. The patterns practiced in these two lessons are the same ones your frontend code will use. The exercises are structured in the same order the schema was built: basic model queries first, then references, then components, then remote data. If a query returns unexpected results, it is a signal about the schema or content, not a problem with the query itself. By the end of lesson 7.2, you will have: - Queried all major schema features: models, references, components, remote fields, and top-level remote fields - Created, updated, published, unpublished, and deleted a product entry programmatically - Confirmed that every schema decision made in lessons 1 through 5 is reflected in the API ## Lessons in this section | Lesson | What you will do | |---|---| | [7.1 Write queries](/docs/getting-started/tutorial/tutorial-write-queries) | Run queries for models, references, components, remote fields, and top-level remote fields in the API Playground | | [7.2 Write mutations](/docs/getting-started/tutorial/tutorial-write-mutations) | Create, update, publish, unpublish, and delete a product entry programmatically using the Product model mutations | For the complete Content API reference, see [Queries](/docs/api-reference/content-api/queries) and [Mutations](/docs/api-reference/content-api/mutations). ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 2 - References Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-references-overview This section covers adding reference fields to the models built in lesson 1.2. References connect models to each other. The connections you configure here are what make it possible to query a product and receive its categories in a single API call. Without references, a product entry has no connection to its categories, and a landing page has no connection to its blog posts. This is why references are a critical part of the schema. By the end of lesson 2.1, the following model relationships are configured: - Products connected to Product categories (many-to-many, two-way) - Landing page connected to Blog posts, Product categories, and Seller information (one-way) ## How references work The way you configure reference fields determines the following: **Type** controls which models can be referenced. Selecting a single model means only that model's entries can be connected. Selecting multiple models creates a union reference. **Direction** controls which side of the relationship can be queried. A one-way reference allows querying only from the model where the field lives. A two-way reference adds a reverse field to the referenced model, so you can query from either side. **Cardinality** controls how many entries can be connected. The combination of direction and cardinality produces four reference patterns: | Pattern | What it means | When to use it | |---|---|---| | One-to-one | One entry connects to one entry | A landing page linked to one seller information entry | | One-to-many | One entry connects to many entries | A landing page linked to multiple blog posts | | Many-to-many | Many entries connect to many entries | Products assigned to multiple categories | | Many-to-one | Many entries connect to one entry | Multiple landing pages linked to one seller information entry | The references created in this lesson impact the queries in lesson 7. For the complete reference field documentation, see [References](/docs/developer-guides/schema/references). ## Lessons in this section | Lesson | What you will do | |---|---| | [2.1 Configure reference fields](/docs/getting-started/tutorial/tutorial-configure-reference-fields) | Add reference fields to the `Product` and `Landing page` models and configure their type, direction, and cardinality | ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 5 - Remote sources Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-remote-sources-overview This section covers connecting the e-commerce project to an external REST API and making its data queryable through the Hygraph API alongside native Hygraph content. Remote sources require a Growth plan or higher, or a [30-day trial](/docs/getting-started/update-billing). Without this section, the schema can only return data stored in Hygraph. After completing the lessons in this section, a single API call to Hygraph returns both Hygraph content and external review data. No separate API request is needed, and no data is migrated or duplicated. The three lessons build on each other in sequence. The remote source must exist before adding remote fields. Remote fields must exist before the top-level remote field can be tested against real data. By the end of lesson 5.3, the project schema includes: - A REST remote source connected to the Hygraph demo API (`HyDemoAPI`) - A remote field on the `Product` model that fetches reviews scoped to each product entry - A top-level remote field on the `Query` model that fetches reviews independently of any product entry ## Lessons in this section | Lesson | What you will do | |---|---| | [5.1 Add a remote source](/docs/getting-started/tutorial/tutorial-add-remote-source) | Connect the HyDemoAPI REST endpoint to the project schema and define the custom types Hygraph needs to query it | | [5.2 Add remote fields](/docs/getting-started/tutorial/tutorial-add-remote-fields) | Add a remote field to the `Product` model to fetch review data scoped to each product entry | | [5.3 Add top-level remote fields](/docs/getting-started/tutorial/tutorial-add-top-level-remote-fields) | Add a top-level remote field to the `Query` model and run a test query to confirm the remote source is working | For the complete remote sources documentation, see [Remote Sources](/docs/developer-guides/remote-data/overview). ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 9 - Webhooks Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-webhooks-overview This section covers configuring a webhook that keeps the deployed storefront in sync with published content. A deployed storefront is a static build created at a specific point in time. When you publish content in Hygraph, the live site does not automatically update. Setting up a webhook closes that gap. When content moves to the `PUBLISHED` stage, Hygraph sends a POST request to a build hook URL on your deployment platform, which triggers a new build and deploys the latest published content. By the end of lesson 9.1, every time content is published in your Hygraph project, the storefront automatically rebuilds and deploys. ## Lessons in this section | Lesson | What you will do | |---|---| | [9.1 Configure webhooks](/docs/getting-started/tutorial/tutorial-configure-webhooks) | Create a webhook in Hygraph that sends a build trigger to Netlify or Vercel whenever content is published | For the complete webhooks documentation, see [Webhooks](/docs/developer-guides/webhooks/webhooks-overview). ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Wrap-up Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-wrap-up You built a complete, deployed e-commerce website backed by Hygraph. The schema, content, API, storefront, preview configuration, and deployment automation you configured in this tutorial are the same patterns used in production Hygraph projects. ## What you can now do **Design a content architecture from business goals.** You started with four store requirements: product listings, categories, landing pages, and reviews, and translated them into a schema of models, components, enumerations, and remote sources. You can apply this planning process to any content-driven project. **Build a schema in layers.** You built the schema across four sections: models, references, components, and remote sources, because models are interconnected and some connections can only be made after their dependencies exist. This layered approach applies to any Hygraph project regardless of complexity. **Use Content Federation to query external data.** You connected an external REST API to the Hygraph schema using a remote source, added a remote field scoped to individual product entries, and added a top-level remote field that returns external data independently of any content entry. A single API call now returns Hygraph content and external review data together. **Query and mutate content programmatically.** You wrote queries for models, references, modular components, and remote fields using the Hygraph API Playground. You created, updated, published, unpublished, and deleted a content entry using mutations. These are the same operations your frontend uses. **Connect a Next.js frontend to Hygraph.** You configured Content API permissions, created a PAT for draft content access, connected a Next.js project using environment variables, and confirmed published content renders in the browser. **Automate deployments on publish.** You configured a webhook that sends a POST request to your deployment platform whenever a `Product` entry is published, triggering an automatic rebuild without manual intervention. ## Best practices **Start with business goals, not schema fields.** The models in this tutorial came from four store requirements, not from a list of fields someone wanted to store. Knowing what the store must do is what determined the schema structure. **Name models and fields for collaborators, not for yourself.** API IDs like `productSlug`, `categoryName`, and `businessDescription` are readable by any developer or editor who joins the project later. Ambiguous names like `field1` or `titleText` create friction that compounds over time. **Build schemas in layers.** Models are interconnected. Build base models first, then references, then components, then remote fields. Trying to configure everything at once leads to circular dependencies and incomplete field definitions. **Localize at the schema level, not as an afterthought.** Deciding which fields need localization at schema design time is cheaper than restructuring later. ## What to build next Before going deeper on any specific Hygraph feature, consider adding an SEO component to your project. It is something every production project needs. | Field | Type | Notes | |---|---|---| | SEO title | Single line text | Overrides the page title in search results | | SEO description | Single line text | Appears under the page title in search results | | SEO image | Asset picker | Cover image for social sharing. Use a named, compressed image with clear alt text. | | Canonical URL | Slug | Leave blank to default to the page URL. Prevents duplicate content penalties. | Attach the SEO component to the `Product`, `Landing page`, and `Blog post` models using a basic component field. ## Continue your learning ### Schema and content modeling | Resource | What it covers | |---|---| | [Content modeling](/docs/core-concepts/content-modeling/content-modeling-in-hygraph) | The full theory behind content modeling in Hygraph: models, fields, scalars, and system artifacts | | [Components](/docs/developer-guides/schema/components) | Component types, nested components, copy/paste, the 50-instance UI limit, and querying | | [Components or references?](/docs/developer-guides/schema/components-or-references) | How to decide between a component field and a reference field | | [References](/docs/developer-guides/schema/references) | All reference types, directions, and cardinality options | | [Enumerations](/docs/developer-guides/schema/using-enumerations) | Enumeration configuration and API behavior | | [Taxonomies](/docs/developer-guides/schema/taxonomies) | Hierarchical classification structures and the `descendants_of` filter | | [Field types](/docs/api-reference/schema/field-types) | API reference for all field types, input types, and filter options | | [Field configuration](/docs/api-reference/schema/field-configuration) | Settings, validations, and advanced options for every field | ### API and content operations | Resource | What it covers | |---|---| | [Queries](/docs/api-reference/content-api/queries) | Full query reference: filters, pagination, ordering, and localization | | [Mutations](/docs/api-reference/content-api/mutations) | Full mutation reference: create, update, publish, unpublish, delete | | [Content stages](/docs/api-reference/content-api/content-stages) | Default and custom content stages, and how to use them in workflows | | [Content localization](/docs/api-reference/content-api/localization) | Full localization reference beyond what the tutorial covers | | [Assets](/docs/api-reference/assets/assets-overview) | Asset upload, management, and transformations | | [Remote Sources](/docs/developer-guides/remote-data/overview) | Full reference for remote sources, remote fields, and top-level remote fields | ### Deployment and automation | Resource | What it covers | |---|---| | [Webhooks](/docs/developer-guides/webhooks/webhooks-overview) | Webhook configuration, triggers, logs, and retry behavior | | [Deploy to Vercel with webhooks](/docs/developer-guides/webhooks/trigger-static-build) | Step-by-step Vercel deployment automation | | [Hygraph-Netlify integration](/docs/integrations/connect-netlify) | Manual redeploy button and deployment status indicator in the content editor | | [Content Workflows](/docs/developer-guides/project/content-workflows) | Custom review and approval workflows between DRAFT and PUBLISHED | --- # Lesson 7.2 - Write mutations Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-write-mutations In this lesson, you will use mutations to create, update, publish, unpublish, and delete a product entry. The mutations follow a complete content lifecycle: create it, change it, publish it, unpublish it, remove it. After each destructive mutation, you will run a quick query to confirm the change took effect. Running a verification query after a mutation is not just a tutorial step. It is the correct practice for any destructive or state-changing API operation. Hygraph automatically generates five mutations for each model when it is created. For the Product model, those are `createProduct`, `updateProduct`, `publishProduct`, `unpublishProduct`, and `deleteProduct`. They are used here in lifecycle order. ## `createProduct` This mutation creates a new product entry with a name, slug, price, product variant, related product, category assignment, and a placeholder image asset. ```graphql mutation MyMutation { createProduct( data: { productName: "My latest product" productSlug: "my-latest-product" productPrice: 59.99 productVariant: { create: { productType: { create: { Clothing: { size: M, color: Green } } } } } relatedProducts: { create: { title: "Related Products" products: { connect: { productSlug: "plaid-shirt" } } } } productCategories: { connect: { slug: "clothes" } } productImage: { create: { handle: "", fileName: "" } } } ) { productName productPrice } } ``` ```json { "data": { "createProduct": { "productName": "My latest product", "productPrice": 59.99 } } } ``` The mutation uses nested `create` blocks to configure the product variant and related products inline. The `products` connect uses `plaid-shirt`, one of the five core products from lesson 6.1. The `productCategories` field uses `connect` to link to an existing category entry rather than creating a new one. Open the **Content editor** and navigate to the **Product** model. The new entry appears there in the `DRAFT` stage. ![createProduct mutation result in the content editor](/images/docs/getting-started/createproduct-mutations-example.png) ## `updateProduct` This mutation changes the `productName` of the entry created above. The `where` clause uses `productSlug` as the unique identifier because it was configured to be unique in lesson 1.2. ```graphql mutation MyMutation { updateProduct( data: { productName: "Updated Product" } where: { productSlug: "my-latest-product" } ) { productSlug productName } } ``` ```json { "data": { "updateProduct": { "productSlug": "my-latest-product", "productName": "Updated Product" } } } ``` ![updateProduct mutation result](/images/docs/getting-started/updateproduct-mutations-example1.png) The `updateProduct` mutation works on any entry, not only newly created ones. To demonstrate, update the Black leather shoes entry: ```graphql mutation MyMutation { updateProduct( data: { productName: "My black leather shoes" } where: { productSlug: "black-leather-shoes" } ) { productSlug productName } } ``` ```json { "data": { "updateProduct": { "productSlug": "black-leather-shoes", "productName": "My black leather shoes" } } } ``` ![updateProduct mutation second example](/images/docs/getting-started/updateproduct-mutations-example2.png) ## `publishProduct` The entry created above is in `DRAFT`. This mutation promotes it to `PUBLISHED` so it is visible when querying the `PUBLISHED` stage. ![Entry in DRAFT stage before publishing](/images/docs/getting-started/publishProduct-mutations-draftmode.png) ```graphql mutation MyMutation { publishProduct(where: { productSlug: "my-latest-product" }, to: PUBLISHED) { stage productName } } ``` Open the content editor to confirm the entry is now published. ![Entry in PUBLISHED stage after publishing](/images/docs/getting-started/publishProduct-mutations-publishedmode.png) ## `unpublishProduct` This step is optional. Skip to `deleteProduct` to continue the lifecycle. This mutation returns the entry to `DRAFT` only. ```graphql mutation MyMutation { unpublishProduct( where: { productSlug: "my-latest-product" } from: PUBLISHED ) { stage productName } } ``` ```json { "data": { "unpublishProduct": { "stage": "DRAFT", "productName": "Updated Product" } } } ``` ![Entry returned to DRAFT after unpublishing](/images/docs/getting-started/publishProduct-mutations-draftmode2.png) ## `deleteProduct` This mutation permanently deletes the entry. Deletion cannot be undone. ```graphql mutation DeleteMutation { deleteProduct(where: { productSlug: "my-latest-product" }) { productName } } ``` ```json { "data": { "deleteProduct": { "productName": "Updated Product" } } } ``` ## Verify the deletion Run this query to confirm the entry no longer exists. ```graphql query CheckDeletion { products { productName } } ``` ```json { "data": { "products": [ { "productName": "My black leather shoes" }, { "productName": "Blue running shoes" }, { "productName": "Plaid shirt" }, { "productName": "Necklace" }, { "productName": "Headband" } ] } } ``` Your response reflects only the product entries you created. If you completed the additional practice in lesson 6.1, more entries will appear. The Black leather shoes entry may show the updated name "My black leather shoes" from the updateProduct mutation above. The deleted entry does not appear. This verify-after-mutate pattern applies to any mutation in any project. Run a query immediately after a destructive operation to confirm the result. The project now has a queryable API, published content, and a confirmed remote source connection. The next step is connecting a frontend to display this content in a storefront. ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Lesson 7.1 - Write queries Source: https://hygraph.com/docs/getting-started/tutorial/tutorial-write-queries In this lesson, you will run queries against the project's Content API in the API Playground. The exercises follow the same order the schema was built: basic model queries first, then references, then components, then remote data. Each exercise proves that a specific set of schema decisions works as configured. Navigate to the **API Playground** in your project sidebar to get started. ## How queries are generated Hygraph automatically generates queries for each model when it is created. Two queries are generated per model, named after the model's **API ID** and **Plural API ID**. The API ID fetches a single entry. The Plural API ID fetches multiple entries. The **Product category** model is a good example. In the API Playground tree, `productCategory` fetches one category entry and `productCategories` fetches all of them. Expanding `productCategories` in the tree shows all the fields added to the model: `categoryName`, `slug`, `description`, and `products`. ![API Playground with displayed tree](/images/docs/getting-started/api-playground-tree-displayed.png) Queries can be built by selecting fields in the tree or typed manually. All exercises below can be copied and pasted directly into the API Playground. ## GraphQL 1 This query fetches all product categories. The Plural API ID `productCategories` returns multiple entries. ```graphql query MyQuery { productCategories { categoryName description { text } slug } } ``` ```json { "data": { "productCategories": [ { "categoryName": "Clothes", "description": { "text": "You will find clothes here" }, "slug": "clothes" }, { "categoryName": "Shoes", "description": { "text": "You will find shoes here" }, "slug": "shoes" }, { "categoryName": "Sportswear", "description": { "text": "You will find sportswear here" }, "slug": "sportswear" }, { "categoryName": "Urban", "description": { "text": "You will find urban-style items here" }, "slug": "urban" }, { "categoryName": "New arrival", "description": { "text": "You will find our latest arrivals here" }, "slug": "new-arrival" }, { "categoryName": "Decor", "description": { "text": "You will find decor items here" }, "slug": "decor" }, { "categoryName": "Accessories", "description": { "text": "You will find accessories here" }, "slug": "accessories" } ] } } ``` The `description` field uses `text` as the output format because it was added as a Rich Text field in lesson 1.2. Rich Text fields require an explicit output format — `text`, `html`, `markdown`, or `raw`. Omitting the format returns an error. ## GraphQL 2 This query fetches all products in the **New arrival** category using a `where` filter on the category `slug`. ```graphql query MyQuery { productCategory(where: { slug: "new-arrival" }) { products { productName productSlug } } } ``` ```json { "data": { "productCategory": { "products": [ { "productName": "Colorful socks", "productSlug": "colorful-socks" }, { "productName": "Green Hoodie", "productSlug": "green-hoodie" }, { "productName": "Plaid shirt", "productSlug": "plaid-shirt" }, { "productName": "Black leather shoes", "productSlug": "black-leather-shoes" } ] } } } ``` The `products` field is queryable here because of the two-way many-to-many reference configured in lesson 2.1. The two-way direction is what makes it possible to navigate from a category to its products. Your response may differ depending on whether you completed the additional practice entries in lesson 6.1. Entries that were not created cannot be returned. ## GraphQL 3 **Try this yourself:** Find the `productName` and `productSlug` of all products in the `urban` category. ```graphql query MyQuery { productCategory(where: { slug: "urban" }) { products { productName productSlug } } } ``` ## References 1 This query fetches the related products connected to the plaid shirt entry. The `relatedProducts` field is a basic component field added to the `Product` model in lesson 4.2. The component contains a `title` field and a `products` reference field. ```graphql query MyQuery { product(where: { productSlug: "plaid-shirt" }) { relatedProducts { title products { productName productSlug } } } } ``` ```json { "data": { "product": { "relatedProducts": { "title": "Related Products", "products": [ { "productName": "Black leather shoes", "productSlug": "black-leather-shoes" }, { "productName": "Blue running shoes", "productSlug": "blue-running-shoes" }, { "productName": "Headband", "productSlug": "headband" }, { "productName": "Necklace", "productSlug": "necklace" } ] } } } } ``` The `title` field returns `Related Products` for every entry because it was configured as a read-only field with a fixed initial value in lesson 4.1. ## References 2 This query fetches all products in the `sportswear` category along with their product descriptions in HTML format. ```graphql query MyQuery { productCategory(where: { slug: "sportswear" }) { products { productName productSlug productDescription { html } } } } ``` ```json { "data": { "productCategory": { "products": [ { "productName": "Green Hoodie", "productSlug": "green-hoodie", "productDescription": { "html": "

This green hoodie combines comfort and style seamlessly, making it your go-to choice for a casual yet trendy look. Its soft fabric and versatile shade of green make it a wardrobe essential for all seasons.

" } }, { "productName": "Blue running shoes", "productSlug": "blue-running-shoes", "productDescription": { "html": "

These blue running shoes offer both form and function, providing exceptional support and style for your active pursuits. The breathable material and cushioned sole ensure a comfortable experience mile after mile.

" } } ] } } } ```
This response requires the additional practice entries from lesson 6.1. If you only created the core five products, Sportswear may return fewer results. ![Items in the sportswear category](/images/docs/getting-started/product-category-contents-example.png) ## References 3 **Try this yourself:** Query the `sellerInformation` reference on the homepage landing page entry. Find out the `businessName` and `businessDescription`. ```graphql query MyQuery { landingPage(where: { link: "/" }) { sellerInformation { businessName businessDescription { text } } } } ``` ## Components 1 This query fetches the `productVariant` component for the headband entry. Because `productType` is a modular component field, the query uses an inline fragment (`... on Accessory`) to specify which component type to query and which fields to return from it. ```graphql query MyQuery { product(where: { productSlug: "headband" }) { productName productDescription { html } productVariant { productType { ... on Accessory { color } } } } } ``` ```json { "data": { "product": { "productName": "Headband", "productDescription": { "html": "

This white cotton headband provides an elegant and sophisticated touch to your hairstyle. Perfect for completing your look with a blend of fashion and comfort.

" }, "productVariant": { "productType": { "color": "White" } } } } } ```
Inline fragments are required for modular component fields because the API needs to know which component type's fields to return. You can include multiple inline fragments in the same query to handle all possible component types simultaneously. For example, `... on Clothing { size color }` alongside `... on Accessory { color }`. ## Components 2 This query fetches the `relatedProducts` component for the blue running shoes entry, returning product descriptions in HTML format. ```graphql query MyQuery { product(where: { productSlug: "blue-running-shoes" }) { productName productDescription { html } relatedProducts { products { productDescription { html } } } } } ``` ```json { "data": { "product": { "productName": "Blue running shoes", "productDescription": { "html": "

These blue running shoes offer both form and function, providing exceptional support and style for your active pursuits. The breathable material and cushioned sole ensure a comfortable experience mile after mile.

" }, "relatedProducts": { "products": [ { "productDescription": { "html": "

These black leather shoes seamlessly blend sophistication with durability, making them a versatile choice for both formal occasions and everyday wear. The sleek design and high-quality leather ensure a timeless appeal that complements any outfit.

" } }, { "productDescription": { "html": "

This white necklace is crafted from parts of seashells, evoking a relaxed, beachy vibe. Perfect for those looking to add a touch of the sea to their daily style.

" } }, { "productDescription": { "html": "

This white cotton headband provides an elegant and sophisticated touch to your hairstyle. Perfect for completing your look with a blend of fashion and comfort.

" } }, { "productDescription": { "html": "

This plaid shirt exudes a timeless charm, perfect for a casual day out or a relaxed evening gathering. The classic checkered pattern and comfortable fit make it a wardrobe staple for effortless style.

" } } ] } } } } ```
## Components 3 This query filters all products by a value inside the `productVariant` modular component, specifically all Accessory type products where the color is White. ```graphql query MyQuery { products( where: { productVariant: { productType: { Accessory: { color: White } } } } ) { productName productSlug productDescription { html } } } ``` ```json { "data": { "products": [ { "productName": "Necklace", "productSlug": "necklace", "productDescription": { "html": "

This white necklace is crafted from parts of seashells, evoking a relaxed, beachy vibe. Perfect for those looking to add a touch of the sea to their daily style.

" } }, { "productName": "Headband", "productSlug": "headband", "productDescription": { "html": "

This white cotton headband provides an elegant and sophisticated touch to your hairstyle. Perfect for completing your look with a blend of fashion and comfort.

" } } ] } } ```
Filtering on a modular component field uses the component type name (`Accessory`) as a nested key in the `where` clause. The same pattern applies to `Clothing`, `Shoes`, and `Decor`. ## Components 4 **Try this yourself:** Query the `stripes` modular component inside the homepage landing page entry. Find the `productName` and `productSlug` of all products added to the Product Grid section. ```graphql query MyQuery { landingPage(where: { link: "/" }) { stripes { ... on ProductGrid { headline products { productName productSlug } } } } } ``` ## Remote Fields 1 This query fetches all products and their reviews from the remote field configured in lesson 5.2. The `reviews` field lives on the Product model and returns data from the HyDemoAPI remote source scoped to each product's slug. ```graphql query MyQuery { products { reviews { data { name comment rating } } } } ``` ```json { "data": { "products": [ { "reviews": { "data": [ { "name": "Sock Lover", "comment": "These socks are great. They are very colorful and they keep my feet warm.", "rating": 4.5 } ] } }, { "reviews": { "data": [ { "name": "Green Fan", "comment": "This is the absolute best hoodie I've ever had", "rating": 5 } ] } }, { "reviews": { "data": [ { "name": "Runner in Rochester", "comment": "These shoes are great. I've run 100 miles in them and they are still in great shape.", "rating": 5 } ] } }, { "reviews": { "data": [] } }, { "reviews": { "data": [ { "name": "Oregon Person", "comment": "After wearing this shirt for 2 days, I realized it was made of cotton. I am allergic to cotton. I am very disappointed.", "rating": 1.5 }, { "name": "Another Person", "comment": "This shirt is okay. It lost a button, but I sewed it back on.", "rating": 3.5 }, { "name": "Third Person", "comment": "I love this shirt. I wear it all the time.", "rating": 4.5 } ] } }, { "reviews": { "data": [ { "name": "First Person", "comment": "These shoes are both the most comfortable and the most stylish I have ever owned.", "rating": 4.5 }, { "name": "Second Person", "comment": "These would be better if they were red.", "rating": 2.5 }, { "name": "Third Person", "comment": "I've worn these for 3 years and they are still in great shape.", "rating": 4.5 } ] } }, { "reviews": { "data": [] } }, { "reviews": { "data": [] } }, { "reviews": { "data": [] } }, { "reviews": { "data": [] } } ] } } ``` Some products return an empty `data` array. This is expected because the HyDemoAPI only contains reviews for products whose slugs match entries in its dataset. Products with no matching reviews return an empty array, not an error. ## Remote Fields 2 This query fetches reviews scoped to a single product, the plaid shirt, using a `where` filter on `productSlug`. The remote field path uses `{{doc.productSlug}}` as the argument, so only reviews for that specific slug are returned. ```graphql query MyQuery { product(where: { productSlug: "plaid-shirt" }) { reviews { data { id name product comment rating } } } } ``` ```json { "data": { "product": { "reviews": { "data": [ { "id": 3, "name": "Oregon Person", "product": "plaid-shirt", "comment": "After wearing this shirt for 2 days, I realized it was made of cotton. I am allergic to cotton.", "rating": 1.5 }, { "id": 6, "name": "Another Person", "product": "plaid-shirt", "comment": "This shirt is okay. It lost a button, but I sewed it back on.", "rating": 3.5 }, { "id": 7, "name": "Third Person", "product": "plaid-shirt", "comment": "I love this shirt. I wear it all the time.", "rating": 4.5 } ] } } } } ``` ## Remote Fields 3 **Try this yourself:** Query the `reviews` remote field inside the **Product** model for the `blue-running-shoes` entry. Return the `rating` and `comment` for each review. ```graphql query MyQuery { product(where: { productSlug: "blue-running-shoes" }) { reviews { data { rating comment } } } } ``` ## Top-level Remote Fields 1 This query fetches landing page data and review data in a single API call. The `landingPage` and `reviews` fields are at the same level in the query because `reviews` is a top-level remote field on the Query model. It is not nested inside any content model. ```graphql query MyQuery { landingPage(where: { link: "/" }) { landingPageTitle link sellerInformation { businessName slug businessDescription { text } } } reviews(productSlug: "black-leather-shoes") { data { id name product comment rating } } } ``` ```json { "data": { "landingPage": { "landingPageTitle": "Home", "link": "/", "sellerInformation": { "businessName": "My business", "slug": "my-business", "businessDescription": { "text": "This is a description of my business" } } }, "reviews": { "data": [ { "id": 1, "name": "First Person", "product": "black-leather-shoes", "comment": "These shoes are both the most comfortable and the most stylish I have ever owned.", "rating": 4.5 }, { "id": 4, "name": "Second Person", "product": "black-leather-shoes", "comment": "These would be better if they were red.", "rating": 2.5 }, { "id": 5, "name": "Third Person", "product": "black-leather-shoes", "comment": "I've worn these for 3 years and they are still in great shape.", "rating": 4.5 } ] } } } ``` A single API call returned both Hygraph content and external review data with no middleware. This is Content Federation working as configured in lessons 5.1 through 5.3. ## Top-level Remote Fields 2 **Try this yourself:** Query the `reviews` top-level remote field for `productSlug: "plaid-shirt"`. Return only the `product` and `rating` fields. ```graphql query MyQuery { reviews(productSlug: "plaid-shirt") { data { product rating } } } ``` ## What's next Or, go to the [Tutorial overview](/docs/getting-started/tutorial/tutorial-overview) for the full lesson list. --- # Manage billing and plans Source: https://hygraph.com/docs/getting-started/update-billing **Project Owners** can manage project billing and plans by going to **Project Settings > General > Billing**. ## Manage billing ![Billing details](/images/docs/user-guides/update-billing.png) This screen displays information about your current plan, usage, and billing details. To view billing details related to your account, click **Billing details** in the top-right corner of the screen: ![Account - Billing details](/images/docs/user-guides/billing-details-account.png) The account billing details screen includes information about your subscription, invoices, account balance, and stored billing information. ## Manage plan To manage your plan, click **Manage plan** at the top-right of the screen. This view shows a side-by-side comparison of all available plans. ![Manage plan](/images/docs/user-guides/billing-manage-plan.png) You can compare plans on a yearly or monthly basis, and manage your upgrade directly from here. If you see that some plans are disabled for selection, this is because your project goes over the limits defined by those plans. ![Disabled plans in the Manage plan screen](/images/docs/user-guides/billing-over-limits.png) ## Commercial limits The limits for **API calls** and **Content entries** are not updated in real time. These values are refreshed once daily by a scheduled job. Any actions that affect these limits are reflected the following day after the job has run. The **API calls** and **Asset traffic** limits are aggregated across all environments within a project. All other limits are not shared between environments and apply only to the `master` environment. ### Hobby plan | PROJECT CAPABILITIES | LIMITS | | --------------------------------- | ------- | | Content entries | 1000 | | API calls | 500,000 | | AI tokens | 100,000 | | Asset traffic (GB) | 100 | | Seats | 3 | | Asset upload size (MB) | 50 | | Models | 20 | | Components | 10 | | Locales | 2 | | Remote Sources | - | | Content stages | 2 | | Version retention period | - | | Environments | 1 | | Webhooks | 5 | | API tokens | 3 | | PLATFORM CAPABILITIES | LIMITS | | --------------------------------------- | ------ | | Standard roles | 2 | | Custom roles & permissions | - | | Rate limits (uncached requests / RPS) | 5 | ### Growth plan | PROJECT CAPABILITIES | LIMITS | | --------------------------------- | --------- | | Content entries | 10,000 | | API calls | 1,000,000 | | AI tokens | 300,000 | | Asset traffic (GB) | 500 | | Seats | 10 | | Asset upload size (MB) | 200 | | Models | 40 | | Components | 20 | | Locales | 3 | | Remote Sources | 1 | | Content stages | 2 | | Version retention period | 14 days | | Environments | 2 | | Webhooks | 10 | | API tokens | 5 | | PLATFORM CAPABILITIES | LIMITS | | --------------------------------------- | ------ | | Standard roles | 4 | | Custom roles & permissions | - | | Rate limits (uncached requests / RPS) | 25 | ### 30-day trial | PROJECT CAPABILITIES | LIMITS | | --------------------------------- | --------- | | Content entries | 40,000 | | API calls | 5,000,000 | | AI tokens | 100,000 | | Asset traffic (GB) | 2,500 | | Seats | 40 | | Asset upload size (MB) | 1000 | | Models | 150 | | Components | 100 | | Locales | 15 | | Remote Sources | 6 | | Content stages | 3 | | Version retention period | 30 days | | Environments | 6 | | Webhooks | 25 | | API tokens | 10 | | PLATFORM CAPABILITIES | LIMITS | | --------------------------------------- | ------ | | Standard roles | 4 | | Custom roles & permissions | 5 | | Rate limits (uncached requests / RPS) | 50 | ### Enterprise plan | PROJECT CAPABILITIES | LIMITS | | --------------------------------- | -------------- | | Content entries | 1,000,000+ | | API calls | 50,000,000+ | | AI tokens | 2,000,000+ | | Asset traffic (GB) | 25,000+ | | Seats | 200 | | Asset upload size (MB) | Custom | | Models | up to 500 | | Components | up to 150 | | Locales | up to 80 | | Remote Sources | up to 10 | | Content stages | up to 5 | | Version retention period | up to 365 days | | Environments | Up to 10 | | Webhooks | Up to 100 | | API tokens | Up to 30 | | PLATFORM CAPABILITIES | LIMITS | | --------------------------------------- | --------- | | Standard roles | 4 | | Custom roles & permissions | Up to 30 | | Rate limits (uncached requests / RPS) | Up to 500 | ---