Use adaptive rate limiter for manual requests to Shopify
You can hook into the rate limiter Gadget uses for Shopify syncs when making manual requests to Shopify’s API using background actions. Enqueue an action that makes a request to Shopify with the current shop context when you want to transform the response from Shopify:
export const onSuccess: ActionOnSuccess = async ({ api, connections }) => {
// the processCustomOrders action calls the Shopify API
await api.enqueue(api.processCustomOrders, {
// pass the shopifyShop ID to the background action
shopifyShop: connections.shopify.currentShopId,
// ...
});
};Or enqueue the shopify-api-node client call directly for durable writes:
export const onSuccess: ActionOnSuccess = async ({ api, connections }) => {
const shopify = connections.shopify.current;
// enqueue the productCreate mutation
await api.enqueue(shopify.graphql, {
query: `mutation ($input: ProductCreateInput!) {
productCreate(product: $input) {
product {
id
title
}
userErrors {
field
message
}
}
}`,
variables: {
input: {
title: "Cool socks",
},
},
});
};Improved JSON file error handling in code editor
JSON files that can't be parsed now display error messages in the problems drawer. The error details are converted into file positions, similar to the system used in CodeMirror's JSON extension. This allows error squiggles to be displayed in the code editor, enhancing the debugging process.
Updated list of outbound IP addresses
Starting today, Gadget may use 34.171.201.14 as an outbound IP. This IP was announced previously. Starting March 1st 2026, Gadget may also use 136.113.237.21 as an outbound IP. You must update your allowlists with this new IP before March 1st 2026.
Vite 7 upgrade and sandbox restart fix
We've upgraded new apps to use Vite 7. This update addresses a bug related to development app loads during sandbox restarts. The restructuring ensures the Vite client always loads properly, avoiding failed connections and hydration issues with the app.
Multi-session terminal support
We're excited to introduce multi-session support in the Gadget editor's terminal. Users can now create and manage multiple concurrent terminal sessions. A new sidebar UI displays all active sessions, showcasing the current running command or "new shell" if idle.
Sessions persist across drawer events and are automatically managed when environments switch.The assistant now has session awareness, reading from the selected terminal session and routing commands intelligently to avoid interruptions.
Fix orphaned webhooks on filter change
We've resolved an issue where some webhook registrations were orphaned when an action's shopifyFilter changed, leading to duplicate webhooks with different filters.
GGT version release: 2.0.0 (requires Node 20)
With the release of ggt v2.0.0, several major changes have been implemented:
- Node.js 20 or later is now required as Node.js 18 has reached end-of-life and no longer receives updates. Ensure your environment is using a supported version for security purposes.
- The new ggt debugger command has been added. It enables debugging via the Chrome DevTools Protocol on localhost:9229 and includes support for VS Code configuration.
- The .gadget/backup/ directory has been removed. Files will now be permanently deleted instead of being moved, as modern source control covers file recovery more effectively.
- Deprecated the ggt sync alias and removed support for .gadget/sync.json files from ggt v0.4.x.
Update to Tailwind CSS v4
Web applications now start with Tailwind CSS version 4, incorporating updated shadcn components. Documentation is included for upgrading existing applications from Tailwind v3 to v4.
To learn more, read the docs.
Select fields for API search queries
You can now specify which fields to search within API calls using the new searchFields parameter. This feature allows you to define the fields that are included in the search and assign relative weights to each field for better ranking control. Select specific fields to search:
const results = await api.post.findMany({
search: "gadget",
searchFields: {
title: true,
content: true,
},
});Boost field importance with weights:
const results = await api.post.findMany({
search: "gadget",
searchFields: {
title: { weight: 2.0 },
content: { weight: 1.0 },
tags: { weight: 0.5 },
},
});This enhancement is available on findMany, findFirst, maybeFindMany, and maybeFindFirst APIs for models with search indexing enabled, requiring framework version 1.5.0+.
Gelly function dateFormat added
dateFormat function has been introduced for Gelly, allowing you to format dates similarly to Postgres's to_char function. This provides a straightforward way to convert dates to strings like 2025-08 with leading zeros for months.Shopify default search and filter field configurations added
Fix for Sentry connection configuration issue
Release of framework version 1.5 with selective indexing
Preact hook support for Shopify extensions (API v2025-10+)
You can now use Gadget’s Preact hooks to read and write data in your Shopify extensions. The @gadgetinc/preact API mirrors
@gadgetinc/react, making migrations easier. useActionForm and component-related hooks aren’t available.
@gadgetinc/shopify-extensions now includes a Preact <Provider />: import { Provider } from "@gadgetinc/shopify-extensions/preact"
Manual index selection on fields
Choose which fields are indexed for sorting, filtering, and search. Sort/filter indexes use Postgres; search indexes use Elasticsearch. This reduces storage costs and gives finer control over query performance and relevance.
The Shopify model schema now shows which fields are indexed, improving visibility into data optimization.
Trigger type schema change
The shopify_sync trigger type now distinguishes between syncs and webhook reconciliations. Webhook-based actions use the new type shopify_webhook_reconciliation. This helps separate sync logic from reconciliation logic and is also reflected in the billing dashboard.
Internal refactor for Preact support
@gadgetinc/api-client-core
has been replaced with @gadgetinc/core. Shared client logic now lives in the generated client, simplifying architecture, improving performance, and reducing dependencies.
Computed fields in public API
Computed fields are no longer returned by default in public API queries — they must now be explicitly selected.
Background action management improvements
- Reintroduced the Cancel all, Delete all, and Retry all buttons for improved user control.
- The index page now uses URL query parameters to define state, making URLs shareable for consistent navigation experience.
Update Shopify CLI to version 3.86.1
App URL mismatch validation for managed installs
ggt v1.7.4 release
ggt push to improve reliability.Context limit warning in assistant conversations
New spend limit feature
Fix sync issues with Shopify models not including shopifyUpdatedAt field
shopifyUpdatedAt field were not correctly getting records updated upon nightly reconciliation sync.Standardize ruleset and sortOrder on ShopifyCollection
rules and sortOrder fields on ShopifyCollection have been standardized to match their incoming REST webhook shapes, ensuring consistency in data.Added missing enums for Shopify API version 25-10
UNLISTED to the status field.
ShopifyFulfillment*: Added CARRIERPICKEDUP to the displayStatus field.Fixed sync errors caused by incorrect Shopify Admin API scope checks
Claude 4.5 deployed as top-level agent
Added `rfmGroup` to shopifyCustomer statistics
statistics field on ShopifyCustomer now includes the rfmGroup attribute for Shopify API versions 2025-04 and later.Paginate all child records in dependent deletes
products/delete webhooks, which include child records in their payloads.Added SEO field to shopifyProduct
seo field has been added to shopifyProduct model. This field is available starting on Shopify API version 2025-01.Aligned shopifyOrder fields with REST webhook payloads
currentShippingPriceSet field on ShopifyOrder and the discountedTotalSet field on ShopifyOrderLineItem to match their webhook REST payload shapes.Shopify app template update to React Router v7
Improved TOML deploy issues
shopify.app.toml file.Standardize discountAllocations field in ShopifyOrder
discountAllocations field on ShopifyOrderLineItem is now transformed to match its REST webhook shape when syncing. This ensures consistency when synchronizing through either GraphQL or webhook.Add syncLast and syncLastBy to Shopify sync
syncLast and syncLastBy parameters to Shopify sync operations. With syncLast, you can limit the number of records synced per model to the most recent ones. For instance, sync only the 50 most recent products. The syncLastBy parameter allows sorting by createdat or updatedat when applying the limit. This is especially useful for faster development syncs and testing with smaller datasets.Fix for app proxy permissions in Shopify connections
We've resolved an issue with Shopify app proxies where sessions were not being set with the correct shop context. This caused issues with access control filters. We have also added the logged in customer to the session model data when customer account authentication is added to your app's Shopify connection configurations
Fixed erroneous file data requests in product webhooks
Gadget now correctly checks the currently granted scopes for each shop before requesting product media data, preventing unnecessary errors when scopes have not been granted. This also fixes a bug where product media positions were only updated during syncs if the read_files scope was missing.
Previously, Gadget would incorrectly attempt to fetch product media file data from Shopify during product webhook processing, even when the shop had not granted the required scopes (read_files, read_themes, or read_images). This resulted in error messages such as: Access denied for fileErrors field. Required access: read_files access scope, read_themes access scope or read_images access scope.
Retry Shopify GraphQL internal errors
Gadget now retries INTERNAL_SERVER_ERROR responses from Shopify's GraphQL API calls up to 6 times, similar to rate limit and REST API errors. This change aids in overcoming Shopify API timeouts and transient errors during syncs and webhook processing. The default Shopify API client from connections.shopify will now retry these errors by default.
Improved Shopify app proxy for tenant setting in GraphQL
Shopify app proxy can now be used to securely set Shopify tenancy in GraphQL. This functionality, previously limited to routes, is now extended to actions. Additionally, connections.shopify includes currentAppProxy if the API trigger is initiated through a Shopify app proxy.
ggt v1.7.3 patch release
This patch release of ggt adds the .shopify folder to the list of always ignored files. This folder is local only and doesn't need to be synced with your Gadget environment.
React 19 for new apps
All new Gadget apps now start with React 19. Existing apps can also upgrade to React 19. For the best experience, it's recommended to update the following packages:
@gadgetinc/react: ^0.22.0,
@gadgetinc/react-shopify-app-bridge: ^0.19.0,
@gadgetinc/react-bigcommerce: ^0.4.0,
@shopify/app-bridge-react: ^4.2React 19 also resolves previous hydration errors caused by third-party scripts, enhancing app performance.
`Open in a new tab` functionality in the docs search results, editor search results, and editor environment selector
Cmd+Click || Ctrl+Click to open in a new tab functionality into the docs search results, editor search results, and editor environment selectorAssistant screenshot support for frontend debugging
Auto-pausing on development environments aborts running syncs
Any running Shopify syncs will be aborted when a development environment is automatically paused.
Connect to the Shopify Dev Dashboard
You now have the option to connect to apps in Shopify's Dev Dashboard when setting up a Shopify connection:

Only organizations with access to the Dev Dashboard will be listed. Connections to the Shopify Partner Dashboard are still supported.
Built-in CORS configuration for HTTP routes
CORS configuration settings are now available in your HTTP routes. This removes the need to manually install the `@fastify/cors` plugin.
Configuration can be set in route.options on individual routes:
import type { RouteHandler } from "gadget-server";
const route: RouteHandler = async ({ request, reply }) => {
await reply.send("hello world");
};
route.options = {
cors: {
// allow only requests from https://my-cool-frontend.com
origin: ["https://my-cool-frontend.com"],
// allow only GET, POST, and PUT requests
methods: ["GET", "POST", "PUT"],
},
};
export default route;Or on a folder of routes using a `+scope.ts` file:
import type { Server } from "gadget-server";
export default async function (server: Server) {
server.setScopeCORS({
// allow only requests from https://my-cool-frontend.com
origin: ["https://my-cool-frontend.com"],
// allow only GET, POST, and PUT requests
methods: ["GET", "POST", "PUT"],
});
}More details, including available configuration options, are available in the docs.
Reduced Hobby plan AI credits from 25 to 15
determineShopThemeVersion util
A new determineShopThemeVersion helper function is now available for developers building Shopify theme app extensions.
You can determine the theme of the pages on a store to decide whether or not a theme app extension is able to be installed:
import { determineShopThemeVersion } from "gadget-server/shopify";
export const run: ActionRun = async ({ connections }) => {
// get the Shopify API client for the current store
const shopify = connections.shopify.current;
if (!shopify) {
throw new Error("Must run in a Shopify context");
}
// Pass the client to the helper function
// to get the theme versions of each page type
return await determineShopThemeVersion(shopify);
};See the docs for more information, including how to check specific pages on a store's theme.
Made images uploaded in the assistant chat clickable
New diff view in deployment summary
Adaptive rate limiter and Shopify sync speed improvements
- When syncing multiple models, the available rate limit is shared efficiently.
- If only one large model is left, it will gradually use more of the store’s limit, speeding up the sync.
ggt v1.7.2 released
Gelly aggregation fix for hasOne relationships
We've updated how Gelly handles aggregations for hasOne relationships. Previously, using a hasOne or belongsTo relationship as the count() argument was incorrectly executed by aggregating the related model. Now, it will properly aggregate the source model instead. This means countDistinct(city) will execute the same as countDistinct(city.id), aligning it with hasMany relationship behavior.
Gelly: Introduced countDistinct() to count unique values, similar to SQL DISTINCT
Gelly now features a new countDistinct() function for distinct counts of field values. While count() counts every non-null value as many times as it appears, countDistinct() counts each unique non-null value only once. The behavior remains similar to count(), supporting related models and filtered counts with optional conditions. Examples can be found in the Gelly reference documentation.
Reintroduces syncs for invalid Shopify shop plans
frozen, fraudulent, or cancelled. This update ensures smoother operations regardless of shop plan states. Additionally, if a shop plan changes from an invalid to a valid state, a log message alerts users. Gadget will update records based on real-time data from Shopify when an embedded app or install request is made.
For sync operations, if a shop's access token is found to be invalid, the uninstall action is triggered automatically.Production typechecking and error display improvements
We've improved the way production typechecking and error displays function in development environments:
- After each deployment, all typechecks, linter checks, and data validation checks are now run to ensure comprehensive problem detection, including uniqueness validations.
- Production problems can now be displayed in development environments, utilizing original alert designs to inform users of production issues.
- The errors indicator only appears when a deployment is completed successfully or with errors, ensuring accurate alerting after deployment.
Fixed GGT_SANDBOX_RELOADING errors from deploying large apps
Fix for app installation edge case when user attempts to install non-existent application
The assistant now gracefully handles scenarios where users attempt to install an app that's been removed from Shopify Partners. Instead of breaking, it recognizes the missing app and guides users to set up a new one:
- "Install failed" label is displayed on the install card.
- AI responds: "I can’t find your connected Shopify app, looks like it was removed. Let’s set up a new one first, then I’ll help you install it on your dev store."
- If deleted from partners dashboard, it prompts: "Your Shopify app doesn't exist on the partners dashboard. Let’s set up a new one first, then I’ll help you install it on your dev store."
Misconfigured views now throw errors instead of being omitted from the API client
Error messages from Shopify CLI now visible as a banner in the terminal
Fixed issue with "install on a store" card remaining in app after installation
Gadget framework version 1.4.0 released
Gadget framework version 1.4 introduces several new features and improvements to enhance your development experience:
- Computed views hooks: Call Gelly computed views that are predefined or inline using the useView hook.
- Vite 6 support: Upgrade to the latest version for improved performance to app loads and caching.
- Lower default action timeout (Breaking change): Default action timeouts are changed from 3 minutes to 15 seconds.
Better access controls in Gelly for relationship traversal results
Improved performance for assistant chats with lots of messages
We've addressed performance issues in the assistant chat UI when handling conversations with over 100 messages. Key improvements include:
- Faster opening animations for the assistant.
- Improved typing responsiveness in the chat input field.
Added detect for the Shopify CLI running in the terminal
Fix for missing hasManyThrough relationship traversals in Gelly
($student: Student) { count($student.followers) } would fail with a "VariableValueScalar" error due to missing support for hasManyThrough relationship traversals in Gelly.Fix for terminal icon color after Shopify CLI closes
cloudflared process continuing to run in the background as a process.Assistant chat now auto-scrolls user messages to top
Type error fixed for useSession(api) in apps without a user model
useSession(api) hook has been updated to no longer produce a type error in apps that do not have a user model.Fixed ability for using app preview routes with params
We've fixed an issue with the frontend preview feature where routes requiring parameters (e.g., /todos/:id) couldn't be previewed correctly. This update ensures that parameter values are filled in properly, allowing for accurate previews of such routes.
Gave information about OpenAI and Sentry connections to the assistant
Improved TypeScript typing for computed fields
Improved Gelly error messaging in problems drawer
Prevent credit charges for zero diff changes
Fix for route preview redirection in Shopify store masquerade
Fix incorrect default permissions for shop-tenanted models
shop didn’t receive the correct default permissions for shopify-app-user. The assistant was incorrectly defaulting tenancy to “off” during the code summoning process, particularly on first-party models (Shopify models).Adding link headers to requests to allow better resource preloading
Model diffs now display using the current app state
Fix for app preview re-render issue when new conversation is started
Delay typechecking actions until package is rebuilt
Assistant now understands how to work with namespaced models
We've improved the Assistant's capabilities by enabling support for namespaced models. Previously, the assistant could not generate data or make model diffs for namespaced models, which posed challenges for technical users.
Fix for chat migration between environments
Web isolated imports: New errors to isolate imports within the web folder
Fix for session type variable, breaking client generation in computed view
We've resolved an issue where using the Session type and variable in named views caused client generation failures. This now allows you to write view logic based on the currect session.
Better error handling when app is missing a package.json files
Improved terminal behavior for initial commands and file navigation
Fix for id field filters breaking live queries
conversationId filtering in live queries by adding a fallback to re-execution when filters can't be evaluated, also addressing related filtering issues on relationships.Resolved unresponsiveness when triggering multiple fix actions
Fixed issue with assistant failing to add Shopify GDPR model
Default writeToShopify action removed from default Shopify templates
writeToShopify action will no longer be added to Shopify applications by default. Instead, the assistant will guide the process of adding it when necessary.Fix for Anthropic errors once an AI chat exceeds a certain length
Deploys no longer cause errors in open assistant conversations
Editor shortcuts now functional in the in-editor docs
We've resolved an issue where global editor keybindings were non-functional in the editor Docs tab. Previously, if you clicked an item inside the docs iframe, keybindings such as cmd+P were not processed correctly, opening the print dialog instead of the command palette. We've implemented a solution to mount keybinding listeners inside the docs, ensuring they are forwarded and processed by the editor.
Fixed broken code validation links in the problem drawer
Billing plan updates
Section added to usage page for displaying assistant credits
We've introduced a new UI section to the billing page that enables users to view the amount of assistant credits they have.
Schema update diffs now displayed as a table
Introducing a terminal in the Gadget editor
Persistent data viewer sorting
updated_at in descending order.

