Migration guide - step-by-step instructions
We recommend following the migration steps in order. If you have questions, please contact us.
Avoid breaking changes
Migrating from SDK v1 to v2 should not cause breaking changes for your users. Please avoid including any breaking changes to your extension’s functionality while migrating. If your extension does include breaking changes, please contact us to discuss.
0. Prepare to migrate
We recommend that you create a temporary site on Netlify to deploy your migrated extension to. You can use this site to install and test the extension in production without impacting your current users.
- Create a new Git branch for your extension and push the branch to your repository.
- Navigate to your team in the Netlify UI and select Add a new site > Import an existing project.
- Follow the prompts to configure a new site based on the branch. Make sure you update the value for Branch to deploy and select the branch from step 1.
- Deploy the site.
As you work on the migration, you can commit and push updates to your Git repository, and then deploy the site to reflect your changes. Once your migrated extension is ready, you can follow the steps documented below to replace the published integration with the code from this branch.
1. Update dependencies
First, start by updating the required dependencies for your project.
-
Install
@netlify/sdk@latest
and@netlify/netlify-plugin-netlify-extension@latest
-
Update the
netlify.toml
file in your project to include@netlify/netlify-plugin-netlify-extension
2. Update files in the project root folder
Next, update the package.json
, netlify.toml
, and integration.yaml
files in the project root folder.
Update package.json
and netlify.toml
In SDK v2, the SDK commands have been renamed from netlify-integration
to netlify-extension
, and we’ve made the following changes:
netlify-extension build
does not accept a--watch
argument. You should usenetlify-extension dev
as a replacement.netlify-integration preview
has been removed. You should usenetlify-extension dev
as a replacement.
Update the package.json
in your extension project to update the SDK commands:
Along with the command changes, there are some other important setting changes to make in the extension’s netlify.toml
file:
The functions directory changes now that API Handlers are endpoints, and you no longer need to set the node_bundler
and headers with the new extension UI.
Rename and update the integration.yaml
file
There are two changes to make to the configuration file:
- Rename the
integration.yaml
file toextension.yaml
. If the file ends in.yml
, rename toextension.yml
. - Remove
integrationLevel
from theextension.yaml
file. All extensions are installed on the team level automatically, so this can’t be customized anymore.
3. Edit methods that have been replaced or updated
We’ve replaced and updated a number of methods and APIs. The following sections outline how to update your extension to reflect these changes. We have another section below for changes specific to connectors.
- Import
NetlifyExtension
and export{ extension }
- Replace addApiHandler with endpoint files
- Replace
context.providerOAuthToken
withcontext.auth
- Replace
onEnable
andonDisable
with endpoints - Replace
getSiteIntegration
withgetSiteConfiguration
- Replace
updateSiteIntegration
withupdateSiteConfiguration
- Replace
enableTeamIntegration
withcreateTeamConfiguration
- Replace
enableSiteIntegration
withcreateSiteConfiguration
- Replace
getTeamIntegration
withgetTeamConfiguration
- Replace
updateTeamIntegration
withupdateTeamConfiguration
Import NetlifyExtension
and export { extension }
In your src/index.ts
file, update the code to import and call NetlifyExtension
, and to export a valid extension
object.
Replace addApiHandler
with endpoint files
API Handlers are now called endpoints in SDK v2. By default, they are now stored in individual files inside the src/endpoints
directory, and use the latest Netlify Functions syntax instead of Lambda-compatible syntax.
Note that you will need to update your endpoints from the Lambda-compatible event and response objects to the web-standard Request and Response objects.
If you haven’t already, make sure to update the extension’s netlify.toml
file to reflect the directory change. You’ll also need to update any paths for calling your endpoints, in your code or while testing locally, from /.netlify/functions/handler/your-endpoint-name
to /.netlify/functions/your-endpoint-name
.
Replace context.providerOAuthToken
with context.auth
If your extension uses OAuth and accesses the token in an API Handler, replace context.providerOAuthToken
with context.auth
.
First make the above mentioned updates to replace addApiHandler
and then update the file to use context.auth
.
Replace onEnable
and onDisable
with endpoints
Remove the onEnable
and onDisable
methods and move your custom logic for the install and uninstall flows into new endpoints that your extension UI will call. More on how to convert your integration UI to extension UI and call endpoints is documented below.
Note that extensions are installed on the team level only. If your integration customized logic for site-level flows, you can specify this using createSiteConfiguration
and deleteSiteConfiguration
.
Replace getSiteIntegration
with getSiteConfiguration
If you’re using getSiteIntegration
in your extension, replace it with getSiteConfiguration
. You will need to pass the teamId
in addition to the siteId
and add a check for configurationResponse
.
Before:
After:
Replace updateSiteIntegration
with updateSiteConfiguration
If you’re using updateSiteIntegration
in your extension, replace it with updateSiteConfiguration
. You will need to pass the teamId
in addition to the siteId
.
Before:
After:
Replace enableTeamIntegration
with createTeamConfiguration
If you’re using enableTeamIntegration
in your extension to create a team configuration, replace it with createTeamConfiguration
.
Replace enableSiteIntegration
with createSiteConfiguration
If you’re using enableSiteIntegration
in your extension, replace it with createSiteConfiguration
and pass in the teamId
.
Replace getTeamIntegration
with getTeamConfiguration
If you’re using getTeamIntegration
in your extension, replace it with getTeamConfiguration
and add a check for configurationResponse
.
Replace updateTeamIntegration
with updateTeamConfiguration
If you’re using updateTeamIntegration
in your extension, replace it with updateTeamConfiguration
, pass in the siteId
, and check for configurationResponse
.
Your code likely also uses getTeamIntegration
before making the call to update, so you will also need to replace that with getTeamConfiguration
as noted in the above section.
4. Remove methods and fields that no longer exist
The following methods and fields are at end of service and should be removed from your extension:
- Remove
enableBuildEventHandlers
anddisableBuildEventHandlers
. Build event handlers run on every site when a user installs an extension on a team. If this is undesirable behavior, refer to the section on the migration overview page to learn how you can add a safeguard for this.
5. Replace Integration UI with extension UI
We are excited about the brand new extension UI functionality and the opportunity it provides to build rich user experiences on top of the React ecosystem. However, because it is a complete replacement, migrating Integration UI to extension UI is not a straightforward change.
To help with this migration, the SDK includes a migration helper that will add extension UI boilerplate files to your new extension.
The following sections provide some more details about the change, how to migrate, and some sample code.
What’s changed
Integration UI is a custom UI framework that sends messages to the Netlify UI, communicating what UI state and interactivity the Netlify UI should set up on your extension’s behalf. Extension UI, on the other hand, allows you to write a single-page React application that Netlify renders to sandboxed iFrames in different locations within the Netlify UI.
The way extensions work is also more flexible than before. While extensions were previously installed to sites, they are now installed once on a team and then configured on individual sites. To support this flexibility, your UI and endpoints may need to change to accommodate this change. For example, while Integration UI surfaces always modified a site, some extension UI surfaces exist to modify a team instead.
While migrating your UI involves manual work, we hope you’ll ultimately find building on top of the React ecosystem easier and more familiar than working with a bespoke UI framework.
For more information about all of the components and surfaces available, refer to the extension UI reference docs.
How to migrate
The specifics might differ depending on what you built previously but here are some rough steps for migrating to extension UI:
- Read through the extension UI documentation to get a sense of how it works.
- Run
npm create @netlify/sdk@latest -- --uiMigration
to add extension UI boilerplate files to your extension. - Modify the generated extension details and top-level site section surfaces for your extension.
- The extension details page is a new surface. If your extension offers an OAuth connection, you should add a
<ProviderAuthConnection />
component to your extension details page surface. - If your extension has a connector, and you answered yes to this question during the
--uiMigration
wizard, you should also have surfaces generated for Connect, the visual editor, or both.
- The extension details page is a new surface. If your extension offers an OAuth connection, you should add a
- If required, move any endpoints defined using
addApiHandler()
in yoursrc/index.ts
into individual files in thesrc/endpoints
directory. For example, an API handler defined byaddApiHandler("my-function", ...)
should be moved tosrc/endpoints/my-function.ts
.- You’ll also need to update your functions from Lambda-compatible syntax to use the latest Netlify Functions syntax and wrap them with
withNetlifySDKContext
to access the Netlify SDK client. Refer to the endpoints documentation for an example. - If you haven’t already, make sure to update the extension’s
netlify.toml
file to reflect the directory change. - You’ll also need to update any paths for calling your endpoints, in your code or while testing locally, from
/.netlify/functions/handler/your-endpoint-name
to/.netlify/functions/your-endpoint-name
.
- You’ll also need to update your functions from Lambda-compatible syntax to use the latest Netlify Functions syntax and wrap them with
- If your endpoints include any site-specific logic, make sure they are not invoked by surfaces that operate only on teams. For example, the extension details page surface.
- Finally, when you’re ready, remove your old Integration UI files including
src/ui/index.ts
.
Migrated form example
Because migrating from Integration UI to extension UI involves a change of frameworks, and because each extension has a different UI experience, it’s challenging to give detailed instructions for how to migrate from one solution to the other.
To provide a sense of how the code might change, here is an example of a form created with Integration UI and a new version created with extension UI.
With Integration UI, a form within a card might be defined like this:
The equivalent UI in extension UI would be:
6. Update code for connectors
SDK v2 adds support for developing extensions for Netlify Visual Editor along with Netlify Connect. To support both features, we’ve made a few changes to the SDK that you need to apply to your extension.
- Define which feature the connector supports
- Set
autoFormatGraphQLTypesAndFields
to true - Update removed connector-related APIs and fields
- Add extension UI for your connector
Define which feature the connector supports
All connectors must specify which Netlify features it supports. It can be Connect, the visual editor, or both.
Set autoFormatGraphQLTypesAndFields
to true
All existing connectors should set autoFormatGraphQLTypesAndFields
to true
. Once set to true
, Netlify will format GraphQL field and type names to use pascal and camel case. Previously, this would happen automatically for all connectors.
If autoFormatGraphQLTypesAndFields
is set to false or not defined at all, GraphQL fields like field_name
in the original data source will be field_name
in the GraphQL API. Sites that currently query a data layer’s GraphQL API will be expecting fieldName
instead.
To avoid breaking API queries for your users, set the autoFormatGraphQLTypesAndFields
to true:
Update removed connector-related APIs and fields
The following connector-specific API and fields are no longer available.
- Remove
enableConnectors
anddisableConnectors
- Replace
define.nodeModel
withdefine.document
- Replace
connector.event
withconnector.sync
- Replace
connector.defineOptions
with an update toaddConnector
- Replace
connector.init
with an update toaddConnector
Remove enableConnectors
and disableConnectors
Both of these methods have been removed. When a user enables an extension on a team, we automatically enable the connector for you.
Replace define.nodeModel
with define.document
If your connector uses define.nodeModel
, that API has been replaced by define.document
.
Replace connector.event
with connector.sync
If your connector uses connector.event
, that API has been replaced by connector.sync
.
If your connector uses this API, you can pass a single function to connector.sync()
instead and use isInitialSync
to determine which logic to run.
If you previously set connector.event('updateNodes', false)
to ensure every sync is a full data sync (with no caching), you need to configure your connector with deltaSync
set to false. This will disable caching between data syncs:
Replace connector.defineOptions
with an update to addConnector
Update your extension to remove connector.defineOptions
and instead define options in extension.addConnector
:
As part of the migration, you will also need to add extension UI for your connector and you will be able to remove the .meta
properties for each of these options then. For now, you can leave them in for reference while you build your extension UI.
Replace connector.init
with an update to addConnector
Update your extension to remove connector.init
and instead define the initial state in extension.addConnector
:
Add extension UI for your connector
With SDK v2, connectors must include code to add extension UI that we will render in the Netlify UI for Connect users — this is in addition to defining configuration options in the extension itself.
To add extension UI for your connector, follow these steps:
- Read through the extension UI documentation to get a sense of how it works.
- Run
npm create @netlify/sdk@latest -- --uiMigration
to add extension UI boilerplate files to your extension. When you receive the promptDoes your extension have a connector?
, make sure you specify yes and the boilerplate will include a surface for Connect. - Update the boilerplate files to create a configuration form to display for users in Connect when they add a data source using your extension. The fields should match what you defined as configuration options. Refer to the add a surface doc for an example of a form you can add.
- Add an endpoint to handle the form submission using
createConnectConfiguration
.
You can preview the form while you work by following the instructions on how to develop extension UI locally.
After you add extension UI for your connector, you can remove any meta
properties on the options defined using extension.addConnector
. Note that leaving them in won’t result in errors.
7. Publish a private extension to test in production
Once you’re ready, you can publish a temporary private extension to test in production.
Add a details.md
file to your root folder with information for your user
Follow the updated details on how to prepare your extension for publishing, and add a details.md
to the root of your project to provide in-app documentation. You’ll be able to preview the rendered documentation in the Netlify UI once you publish the private extension.
Publish a private extension
Follow the steps to publish a private extension using the temporary site you set up for your migration branch.
Test your private extension
Once published, you can install the extension on your team and test.
- In the Netlify UI, navigate to the Extensions section for your team.
- Select Created by your team and find your private extension in the list.
- Select the extension and then select Install on the details page.
8. Replace your published integration with the new extension
Once you’re ready to replace your published integration with your new extension, complete the following steps:
- Merge your temporary extension migration branch into the production branch that contains the code for your published integration.
- Make sure this triggers a new production deploy.
- Once the deploy is published, your old integration will be replaced by your newly migrated extension. The new extension will be available to all teams that have it installed. Depending on what your extension does, users may need to rebuild and redeploy their sites to run the new extension.
- To avoid confusion, we recommend deleting the temporary private extension and temporary site you set up for your migration branch. You will need to uninstall the extension from any sites that you tested it with before you can delete the extension and the site.
Contact us for support
If you have questions or run into issues while migrating, please contact us through Netlify support or through the technology partner program.