With the upcoming deprecation of private metafields, Gadget now supports app-owned metafield namespaces. To sync or register webhooks for app-owned metafield namespaces you may use either the app-{your-app-id}--{some-namespace} or $app:{some-namespace} reserved namespaces when setting up model fields. For more information check out our guide here
New Gadget apps can now be created with built-in support for Email/Password authentication. The starter Web and AI template now includes customizable actions enabling users to sign-up, sign-in, verify emails, reset and change passwords. Gadget now takes care of email sending by default with actions, but users have the flexibility to integrate with external email providers such as MailChimp and SendGrid as well as customize the default email templates. For more information check out our docs.
Each action is passed an emails object, which is an instance of the GadgetMailer (a Gadget wrapper for NodeMailer), that is primarily used to handle and facilitate the sending of emails.
Gadget now supports Shopify API version 2023-10. For the full list of changes see the API changelog here.
The Shopify connection will automatically fetch all recent data in the background daily. This ensures we have all of the shop's data in the case of a missing webhook or for models that don't have webhooks.
Users have asked for control over whether or not Gadget should run an automatic daily sync for models that do not have webhooks. Starting with this change Gadget supports opting out of the automatic daily sync for models that do not have webhooks.
Gadget frontends can now subscribe to backend data changes in realtime with the live: true option for the React hooks.
Pass live: true as an option to one of the finder hooks, and the browser will watch for new data, fetch it, and re-render automatically when it changes within your backend.
For in depth details check out our realtime queries doc.
We've added a new step to the deployment flow of your app: setting up database. This ensures all the new models and fields you've added since the last deploy are ready to go before your app finally hits production.
With this change, expect the following changes during deploy:
1. If you've added or changed a field on a model that has a lot of records in production, your deploy may take some time, but you should see progress on how many fields have been set up so far.
2. If you've added a uniqueness validation to a field, your deploy will fail if the data for that field isn't unique in production.
Gadget now supports authenticating requests made from Shopify Checkout Extensions using Shopify's Session Token feature. Inside a checkout extension that has the network_access capability, you can make a request to your backend Gadget API or an HTTP route.
Within your backend Gadget app, you can access the connections.shopify.current object, knowing that the request is provably for a given shopify shop
Requests made from a Checkout extension are made by customers, and will use the unauthenticated role. This is different than requests made from your embedded app, which also use Session tokens, but are for merchants. Requests made by merchants in the embedded app will use the shopify-app-user role.
For in depth detailes check out our building shopify extensions doc.
Gadget now supports caching responses from HTTP routes in its high-performance, pre-configured CDN. If your route serves a Cache-Control header, the response will be cached at the edge and sent back to your users as you see fit.
For more information check out our guide on response caching here.
Previously, Gadget recommended that Shopify applications use the /shopify/install URL for their App URL configuration value in Shopify. This URL is where Shopify sends both uninstalled merchants that need to install an app, and already installed merchants that want to start using the application. The performance of this route is sensitive because it is the first touchpoint each merchant has with your application.
Gadget now supports a high-performance entrypoint for Shopify applications that improves an app's LCP time. This route will trigger the OAuth and install flow for new merchants, and redirect existing merchants to / for rendering the frontend experience of your application. This route is optimized by Gadget to be as fast as possible and does not require starting up the serverless runtime for your application, which means the performance will be much more predictably low.
Gadget will default to using this URL for new applications.
For existing applications, you can take advantage of the new route by changing your App URL to be <your app domain>/api/shopify/install-or-render.
For example, for a Shopify app built with Gadget at shopify-example.gadget.app, you can set these values:
Development App URL: https://shopify-example--development.gadget.app/api/shopify/install-or-render Production App URL: https://shopify-example.gadget.app/api/shopify/install-or-render
Gadget now supports defining Scheduler triggers using cron syntax. If you have strange or specific intervals you need to run your jobs at, you can use a cron expression for maximum precision!
Previously, when processing webhooks from Shopify, Gadget would populate any belongs to field pointing to the shopifyShop on Shopify models. Now, Gadget will only set the value of the default shop field, and leave any other BelongsTo fields to be set by application code.
Previously, when a field was changed from the string field type to the encrypted string field type, Gadget would erase the data in the field and require data to be re-loaded into it.
Now, no data will be erased, and Gadget will transparently encrypt the data at rest without needing it to be reloaded. Existing data will be preserved.
New Gadget apps can now be created with built-in support for Google OAuth driven authentication. The starter App.jsx template now includes a basic Sign in with Google button and renders a User card with some user information when signed in. Behind the scenes Gadget uses OAuth to authenticate the user with Google, and then creates a User record. The default behavior can be extended with the new @gadgetinc/auth fastify Auth plugin as well as by working with the actions on your User model.
In addition to the back-end model and oauth support, we've added some new front-end components to help you build your own authentication flows. The @gadgetinc/react package now includes several new React hooks and components to help you build your application with users in mind. Read more about it in the @gadgetinc/react docs .
Gelly syntax and usage errors will now be displayed in the Gadget editor with red underlines.
Introducing improved support for seamless integration of your-session-token in the Authorization header for API requests. This update enables the utilization of session tokens generated through the use of checkout extensions' useSessionToken. Previously, attempts to employ such tokens led to error responses from Gadget.
Gadget now uses Vite version 4.4.9 for all applications. Vite 4.4 brings many performance improvements and no breaking changes.
For more on what's new in Vite 4.3 and Vite 4.4, see the Vite blog: https://vitejs.dev/blog/announcing-vite4-3.html
Gadget now supports syncing Shopify's Gift Card resource.
Shopify only supports Gift Card API access for Shopify Plus stores, and only with Custom apps provisioned within the Shopify Admin. Shopify also doesn't expose webhooks for Gift Cards, so the Gift Card model is synced only.
When creating a new Gadget app, the automatic deployment of the Production environment will no longer take place by default. Instead, all apps will begin with a development environment and will require a deployment from the Gadget editor to set up the production environment.
Previously, Gadget stored the list of roles assigned to a Session or a User using internal, unique identifiers for Roles called role keys. Role keys are annoying to retrieve and use, so now Gadget accepts a list of role names as input for the Role List fields. In the Public API, roles return values are unchanged, and still returned as objects like {name: "readers", key: "readers"}. The Internal API now returns the list of roles as a list of role names, instead of role keys.
For backward compatibility, both the Public API and the Internal API still accept role keys as input, but role names should be preferred.
Each Gadget app's generated JS client uses the production-grade urql GraphQL client under the hood. The generated JS clients now depend on urql v4 for improved performance, smaller bundle size, React <Suspense/> support, and more. The next version of your app's JS client will depend on the newer version of urql, and you must upgrade @gadgetinc/react to match.
Models can now be filtered by if a Boolean field is set at all or not. Use { filter: { someBooleanField: { isSet: true }}} to only return records where the field is set to something (either true or false), and use { filter: { someBooleanField: { isSet: false }}} to only return records where the field is not set (equal to null).
Gadget will now correctly set your Gadget metafield fields to null if they have been cleared in Shopify. They were previously left with the last non null value.
Gadget now supports b2b models (i.e. Company models) and their associated webhooks that are only available for stores with Shopify Plus Partners accounts.
See the company Shopify API: Admin GraphQL docs for more information about the resource.
Previously, Gadget application's API references were accessible to anyone with the URL. Now, API references are only accessible to Gadget users who can edit the application. If you'd like to grant a user access to your application's API reference, add them to your Team so they can access your application's editor.
The useFetch API client hook now supports a sendImmediately option for explicitly controlling if the request should be sent immediately on render or not.
See the useFetch documentation here for more information on the sendImmediately option.
Gadget models can now store Vectors using the vector field type. Vectors allow sorting and filtering by vector similarity, which is useful for building semantic search and AI applications.
See the vector field docs and the building AI apps guide for more information.
We fixed a bug that prevented you from serving static files like images, text files, etc. from /public in your development environment.
When using the “Go To Definition” for Gadget types in the code editor you’d be taken to the file of the definition, but not the definition itself. We’ve fixed this bug, and you’ll now be taken to the correct line in the file as well.
We’ve improved the experience of how you manage files and folders in Gadget. Drag files and folders to rearrange them. Move them up and down your file tree without having to rename the path, and the destination folder will be highlighted as you go. You can read more about it in this blog post.
Early on we caught a few bugs around overwriting files and folders with duplicate names which we addressed.
You can now access environment variables in your frontend if the variable name starts with GADGET_PUBLIC.
The function signature for HTTP route handlers were inconsistent with effects elsewhere in Gadget. The other effects deconstructure out useful things automatically, which is a better experience because you don't have to do it yourself when you need these.
We’ve updated routes to do this too, and updated the routes documentation with these changes.
In some circumstances you could trigger an infinite loop in your frontend when using useEffect. It happened because the object returned had a different identity, even if nothing had changed. This was a bug, and has been fixed. If nothing about the query has changed, you get back the same data object, and no-run takes place.
When using the Gadget code editor you get TypeScript powered editor hovers in your code files. That didn’t work as expected for files in the frontend folder, which displayed “any” on hover.
This has been fixed, and types now show as expected on hover for all your code files.
When a Shopify merchant installs your app on their store Shopify fires a webhook to your Gadget app. The webhook is captured by the Shopify Shop model, and a record is created with information about the merchant's shop.
We’ve renamed the Shopify Shop model API action that captures this from “create” to “install” to make it clearer to developers what triggers it.
Apps created before this change will be unaffected since it would be a breaking change to change the action name.
After forking an app that had a Shopify connection, the connection page in the newly forked app displayed a banner asking you to complete the connection setup. If you clicked it, you were shown a screen with null app URL and allowed redirection URLs. That was a dead end and a bug, so we fixed it.
When you created empty folders on your computer with the ggt CLI Filesync they didn’t appear in Gadget until you created a file in them. That’s not a great experience, so we fixed it. Now empty folders get synced from your local computer to Gadget.
During the closed beta of Gadget's hosted React frontend there was a bug where the embedded Shopify app wouldn’t render correctly if the merchant loaded the page after you had edited your connection to add more scopes.
The expected behavior is for the embedded app UI to display the Shopify OAuth flow, where the merchant can grant access for the newly added scopes. This has been fixed.
There was a bug in a ggt Filesync flow where users ran the command `ggt sync --app foo` without being logged in. If you weren't already logged in this command should first log you in, then check if you have an app named 'foo'. But this was made in the reverse order which led to the CLI returning an “unknown application” error. This works as expected now, so sync away!
We've improved the default behavior of the logs viewer in development. When you browse to the logs "live mode" will automatically be on so you see the latest log entries without having to click a button. Your previously selected time window will still be used, and defaulted to a 5 minute window otherwise. And any logs search parameters used previously will be cleared automatically. More logs, less clicks.
Any app you create automatically has a NODE_ENV variable with values ‘development’ and ‘production’ for the respective environment.
But when you forked an app, these values didn’t propagate and were set to null. The root cause was that we don't want to auto-copy keys stored in the forked apps since these may be sensitive. We’ve made an exception for NODE_ENV. Keep forking.
Shopify apps built on Gadget automatically pass the technical requirements in Shopify’s app store review process. During the closed beta of Gadget’s hosted frontends we identified that apps using the frontend for the embedded Shopify app failed Shopify's Content Security Policy headers check, so we promptly fixed that before any users were impacted.
If you hit the 'Enter' key while on the Shopify scope selection page in Gadget we treated that as you clicking the 'Confirm' button. That’s probably not what you'd expect, and not what we wanted. So that’s gone. Hit enter all you want.
Make use of the full Shopify webhook payload in your code effects with the new `trigger` parameter.
Gadget handles Shopify webhook subscriptions for you by automatically splitting a single webhook payload into multiple data models. For example, products/create webhooks are split into the Product, Product Variant, Product Image, and Product Options models.
We now expose the complete webhook in a new parameter, readily-available in your Shopify model’s code effects through the trigger parameter. Learn more.
Previously when you renamed files Gadget wouldn't update references to those files in effects, conditions, and validations. That has been fixed. Rename away.
The write_pixels and read_customer_events were added to the Shopify API scopes. They should have been there all along, but weren't. Now they are.
Added the ability to sort columns, bulk delete, use keyboard shortcuts, and create new records. Maybe not revolutionary, but at least you can sort now. Learn more.
The `syncAllShops` global action which enqueues a Shopify Sync for all Shopify shops can be one of the meatiest things your app will process. That's why we've made sure it isn't transactional by default, and has upped to the maximum timeout of 15 minutes.
We've added a Billing and Usage screen to your Gadget Account area to report on resource usage by all your apps, and allow you track if you're staying within your plan. Learn more.
If you have an intermittent error that causes your application to crash, Gadget would previously only restart your application if it scaled to 0, or if you made a change to your application.
We now will try to restart the application rapidly if it has just crashed, with exponential backoff to once every 5 minutes steady state. We don't suggest you try to crash your app, but if you do we'll automatically recover it more quickly!
We'll now ensure shops with `null` granted scopes aren't synced. Shop records generally shouldn't have null granted scopes, but if you are adding shop records with the Internal API that are not installed, Gadget will no longer attempt to sync them.
Trying to sync shops with Shopify plan_name 'frozen' or 'cancelled' returns an error, so we won't do that anymore. Less syncs, less problems.
When you need to refer to the docs of the app you're working on it can be confusing to get served the docs of one of your other apps. So we fixed that.
We've improved the error reporting when sync or global sync actions enqueue a sync with invalid parameters. We all do it sometimes, but at least now we'll get clearer errors to help us fix it.
Shopify syncs will fail if you’re using resources that include buyer data, but haven’t filled in the Shopify Enhanced Data Protection survey. We made the errors clearer when that happens, and link you to the appropriate place in Shopify for you to address this. To learn more about Shopify's requirements read their docs.
We improved the performance and scalability of the /api/client/web.js and /api/client/web.min.js script tags for faster performance in high-traffic places like the Shopify Storefront. Minimum packages for maximum speeds.
Remember when you last deployed? Up until now you had to, because we didn't show it in Gadget. But now we do.
We want to say that the title is self explanatory, but that's rude. So we'll just say that the your experience with the Gadget web editor should be better after we've improved the performance by 20%.
We've improved the app reload performance after a change to an app's schema by 20%.