Learn how to migrate an existing private app to the projects framework.
2025.2
).
This guide will walk you through the following:
hsproject.json
and app.json
configuration files.
2025.2
of the developer platform, based on the existing features you had set up (e.g., an app card built using UI extensions).hsproject.json
file, all other configuration files follow a predictable naming scheme (*-hsmeta.json
where the *
is based on the specific directory or component) and all share the same top-level properties:2025.2
schemas that you can reference, you can download a boilerplate template:
npm install -g @hubspot/cli@latest
and connected it to your account using hs account auth
command. If you haven’t installed the HubSpot CLI yet, run npm install -g @hubspot/cli
. You should be on v7.6.0
of the CLI before proceeding.private
distribution and static
auth.*-hsmeta.json
schema files to your existing project to ensure the specifications match when applicable. Note that the template should be used as a reference, but not edited directly, as it’s recommended that you make any edits in the cloned version of your project as outlined above.2025.2
of the developer platform is detailed in the app configuration guide.
hsproject.json
involve minor changes to the name
and platformVersion
properties, as outlined in the code blocks below:
Before:
hsproject.json
file in your project lives in the same location in the new developer platform, but you’ll need to update the platformVersion
to "2025.2"
. You may also want to update the name
field with a unique name so that it doesn’t override your existing project when you upload it. For example, if the name of your existing private app was named My private app
, you might want to append (Developer Platform v2025.2)
or something similar to distinguish it from the old app.
src/app/app.json
):
src/app/app-hsmeta.json
):
app.json
file. These config details for your app are now specified with your app schema file in the /src/app/app-hsmeta.json
file. The key changes between your old app.json
config and the new app-hsmeta.json
config include the following:
public
property has been replaced with distribution
and should be set to private
. Note that the type
sub-property of the auth
field should be set to static
, which will restrict installation of your app to a single account. Learn more about app distribution and authentication in the app configuration guide.auth
field, and are split out between requiredScopes
, conditionallyRequiredScopes
, and optionalScopes
. Learn more about specifying each of these scope types in the app configuration guide.extensions
property from your previous project, since the property is not present in the new app-hsmeta.json
file. Any previously configured UI extensions (e.g., cards on the CRM record page) are managed using the cards/
directory of your project. Within that directory, card configuration details are specified in a *-hsmeta.json
file, alongside the component code for your card provided in a .jsx
file that’s referenced using the entrypoint
property of the *-hsmeta.json
file.webhooks
property from your previous project in the new app-hsmeta.json
file, as webhooks are configured and managed using the webhooks/
directory of your project. Learn more in the migrate webhook subscriptions section below.src/app/extensions/card.json
):
src/app/cards/example-app-card-hsmeta.json
):
cards/
directory of your project, replacing the old extensions/
directory from your old project. Within the new cards/
directory, card configuration details are specified in a *-hsmeta.json
file, alongside the component code for your card provided in a .jsx
file that’s referenced using the entrypoint
property of the *-hsmeta.json
file.
To port over your legacy app’s UI extension code, copy any relevant values over from your legacy app.json
into the associated properties in the *-hsmeta.json
file in the cards/
directory, keeping the following changes in mind:
type
property has been changed from "crm-card"
to "card"
.uid
property has been moved up from a sub-property of the data
field and is now specified at the top-level of your config.data
property has been changed to config
, which includes the following sub-properties:
title
property has been renamed to name
.description
property allows you to provide more context around the functionality of your card. The description will appear in your app’s project settings.module
property has been renamed to entrypoint
and the value should now be a string that represents the path to your JSX component, relative to the root of your project (e.g., "/app/cards/example-app-card.jsx"
).objectTypes
property has been simplified and is now an array of strings representing the object types where your card should appear (e.g., ["CONTACT", "COMPANY"]
).location
property remains unchanged, and can be set to crm.record.tab
, crm.record.sidebar
, crm.preview
, or helpdesk.sidebar
.example-app-card-hsmeta.json
config file and example-app-card.jsx
JSX component are provided in the src/app/cards
directory.
For a full guide on creating app cards on the new developer platform, check out this article.
src/app/webhooks/webhooks.json
):
src/app/webhooks/webhooks-hsmeta.json
):
webhooks/
directory of your project. Within the directory, subscription details are specified in a *-hsmeta.json
file. The structure of the file is largely similar to the previous webhooks.json
schema in your private app, with the following notable changes:
uid
property must be defined at the top-level of your *-hsmeta.json
file, which should be given a name to differentiate it from other app features (e.g., "migrated_private_app_webhooks"
).type
property must also be defined at the top-level of your *-hsmeta.json
config and must be set to "webhooks"
.subscriptions
and settings
properties remain unchanged from webhooks.json
but must be moved into the config
property that’s defined at the top-level of your *-hsmeta.json
file.src/app/app.functions
from your old project, along
with any associated references to your serverless functions elsewhere in
your project.hubspot.fetch()
API to fetch data. This will require you to migrate any existing service logic that was previously defined in your HubSpot-hosted serverless functions, as well as your private app access token to a third-party hosting platform, such as Vercel, DigitalOcean, AWS, etc.
To migrate over your serverless function logic to a third-party hosting platform:
src/app/app.functions
directory.permittedUrls
property of your top-level app-hsmeta.json
schema file to include the fetch
field. The value of this field should be set to an array that includes the URL of your endpoint hosted in your third-party hosting platform.
hubspot.fetch()
in this guide.