How to Migrate Apps to HubSpot Developer Platform 2025.2

Roger Brown shows how to migrate legacy HubSpot apps to the new CLI-first platform using hs-app migrate and hs-project migrate commands. The new version models apps as code projects with unique identifiers, enabling faster development, source control, and access to 2025.2 features like App Homes, Settings Pages, and Agent Tools.
Chapters
My name is Roger Brown.
I'm product manager on the developer platform team. And today I'm going to, in this particular session, talk about migrating your apps over to the latest version of our platform and basically becoming what we call project-based apps, which are managed with code. We, in the prior session, we talked about the benefits of the developer platform. In this particular session, we're going to talk about what it's like to migrate to, on an app basis, the new platform and do a live demonstration and walkthrough. So again, you have an opportunity. It's definitely not a requirement, but if you want to follow along, I'm going to show you exactly the step-by-step process to do this using two different app types and demo that end-to-end. And then we'll explore some of the benefits of the new platform, talk about the features you get, for migrating to 2025.2, and then also take a look or discuss what's upcoming a little bit. That will be shared out in much more detail coming later on, but a little preview, and then along with questions, we can take some questions like, what are the primary benefits of migrating to 2025.2? And The main difference you'll notice is you're able to make changes more quickly and not necessarily using the user interface, right? So we'll take a, we'll see this in a minute, but basically the, the surface area, the interface for app development is moving away from the UI and in some cases developer API keys to local source code, which can be managed remotely. And using the CLI and other CI tools, you can, you can deploy it and make changes much more quickly from a development perspective and safely with team at scale, right? So the hope is that, you know, this is much more modern feeling experience for most users. And so, you know, you'll kind of recognize it almost immediately, the main difference between these, and then you'll get access to a bunch of new features once you do this. I'll demo in a second what some of those are, but there's a bunch in this particular release and more coming in the future. And the other thing is we tried to communicate this inbound. I think the message is still getting out a bit in the ecosystem, but we're trying to be much more thoughtful and predictable on the timing for our releases. So we plan two annual, uh, semiannual GA releases now. That introduce breaking changes and we support them for 18 months. So that gives you flexibility to choose when you migrate to the latest version of the platform and for what reasons. And you don't, you shouldn't feel stressed or unclear about when or where, where to do that. So there should be much more predictability and we have a page dedicated specifically to the versions that we release now. And the timing along with them. So what are the major changes between, let's say, the, the old version and the new version? Well, the main thing is that it is managed as a project now, which like I mentioned before, is just a framework we use for modeling the app's configuration and features as source code. And then you can still see that represented inside of the user interface inside the developer platform. But it's managed through updates and uploads through the CLI. And along with that, you also get the other benefits of functionality inside of the, inside of the navigation menu and the new unified platform and a bunch of other features that I mentioned in the previous session that you can— I think we have a link that's going out to some of what those are. So hopefully you can take a look at that. And then what stays the same is the configuration itself isn't changing. It's just the way that you're modifying it is changing. So those things stay the same and you get to choose when you make changes. Just the how is different and your installs stay the same. There's no impact at all to customers once you do these migrations. And similarly, like the tokens that they're using and credentials to access public API, all of those stay the same along with the install URLs, which are really constructed based on the scopes permissions that your team requires from installing customers. So none of that changes in the migration process. So when should you migrate? I think this is definitely a question that we can't definitively answer, but here's a little bit of guidance. And so the urgency around this is you're trying to build public apps with new features like App Homes or Agent Tools. You want to take advantage of some of the things that we've done recently and introduce those to your customers and make your apps more useful and valuable to them in their day to day, you'll have— that's a good reason to, to migrate to the new platform. You'll get some of the other benefits we talked about for observability and the CLI process, the tooling side that will help you manage those at scale along with our ecosystem and the partner program as well. Will be, will be very important. If you, if your app still relies a lot on serverless functions, so this is more for not our public app developers or ecosystem, but more like for customers that are using serverless, where the version that I'm going to cover today does not support serverless, so it's not a good fit for you. And similarly, that support is coming soon. We'll talk a little bit more about that later, but we do offer an alternative in the interim, which is to, if you're using public apps, you can use the fetch or even in a privately distributed app, you can use fetch as a way to interact with third-party or your own API endpoints versus using serverless functions almost as like a proxy through those requests. So that is kind of the reasons why. And so what does the process really look like? Well, You start with the CLI. It's a CLI-first experience. We expect most of our developers to be using the CLI daily and not necessarily having to log in or see, you know, the, the UI unless they really need to. So that'll be the first thing that you notice. And in this particular case, we're talking about legacy public apps. And so what you'll run is the hsapp migrate command from the CLI, which I will demonstrate in a second. And then you're going to select kind of the metadata that goes in. In some cases, we don't have all the metadata we need to convert it. So we'll prompt you and ask you to supply that. And then what happens is we generate the local file locally on your computer. So then it will be available to you to see and confirm that nothing has changed. And then from that point on, you can choose to store it and track it in a remote repository like GitHub. Et cetera, or just continue to use it locally and then use the CLI. Once you make changes locally, use the CLI to upload this to the platform. One of the key things about our project's framework and features and identification is the concept of uniqueness across components or features at the app and account level. So one of the, maybe the newer things to learn is what we call UIDs for components. Which give them essentially a name that you'll recognize and define in code. No customer will see that, but this is a way for you to track what the feature is over time and make sure like this, the same feature could have multiple variations essentially, but are all linked to the unique identifier. So that's an important thing that we'll see in a second and that you should learn. And, um, yeah, as I mentioned, it downloads the files locally, so we can inspect them. So just double checking on polls. We have anything before— I think we're going to do a poll after the demo. So let me go back to— or actually, let me start here quickly. So If you weren't able to join the last session, I did talk about this before, but basically I just converted this account to use the new unified platform, which shows me my overview and things about my app. And in this case, I already had two apps that I was managing before I did the conversion. So I can now see those from the legacy apps page. And this actually will represent not just apps listed in the marketplace, but any of your development apps, any apps that you're using for personal customization for your own portal, things like that. So this is the user interface that kind of represents that. So in this case, let's start by taking a legacy public app and we're going to go through the same flow that we saw before. So in that case, I have a portal or sorry, I have the CLI already installed. So I'm not going to demonstrate that, but configuration for the portal should be pretty quick.
Looks like I'm not seeing my terminal.
One second. Let me switch. Now you should see that. So I have a local directory here that I already created for the demo purposes, but I'm just gonna run the hs-app migrate command now. And actually, before I do that, we can just see if you're not familiar with our CLI, you can run helper functions or lags and get information about different commands that you want to run. So in this case, all you have to do is run hs-app migrate. And what will happen behind the scenes is that we are going to look inside of the account that it's configured for. And determine if there are any apps that have not already been migrated to projects. And for those that are found, in this case I have My First Legacy Public App, which we were just looking at in the web UI, is not migrated yet. So that is available to select. But I have another My First Project app which is already running on projects, but an older version of it. So that one is disabled and you can see that information here. So I'm going to choose to migrate this app now, and I have to give it a name. And this is for basically tracking the overall project itself. Oh, let me get rid of this bar one sec.
That's good. Me stop and I'm just gonna have to move that out of the way, I guess. So this.
Okay. So I have to give it a name. In this case, I chose the same name that I had already for the previous app. So I'm going to, I'm going to say that's fine to continue. And what's happening behind the scenes is that it's looking at the state of the app and the features of it, identifying that there is a feature that exists, which is the app itself, which also needs a unique identifier. So I'm going to, uh, I'll just continue with this as well. The thing is that we just have to make sure that whatever you choose for the UID, it's unique for each component. So each app needs its own UID across the entire account. So no matter how many projects you have, each one has to have its own unique identifier. You want to make sure it's something that's meaningful to you in some way to distinguish, you know, that. And so like, if I were to have multiple other features like webhook— well, webhooks is not a good example, but like something like a CRM card or an app card. Each one of those would have to have its own unique identifier, and that helps you to identify it as well. So that migration is now complete, and we can take a look at what was generated locally.
I hope the window shows.
Okay, great. So that came up. Let's go to— I have to increase the font here. Let me—
okay, well, you can see that.
So this was my first legacy public app. This is what was generated locally. So that configuration that's represented in JSON here is matching, uh, what was in, in inside our system at the time that I ran the migration command. So that matches. And then also here you can see that we are now using platform version 2025.2, which is the latest GA release, and it matches the name for the project that I gave it initially. And then at the app level, you can see that the UID for my app is matching too, and that this is an app. In a second, we'll take a look at slightly more complicated project structure, but just wanted to do that quickly. And then let's see if we can take a look at inside of the user interface. Now, if I refresh this, you can see that it drops off legacy apps page because it's no longer managed there. It's managed via projects and it is on the latest version of our platform. Let me find that too. So here we use projects to understand the state of all the changes that were made and the time. You can look at if there are any issues or errors that come up and specifically by components as well as some other settings you can configure for the project itself and track this with your team, right? So if you wanted to see like why the state of the configuration changed, you can use this system to understand that and even go back and to deploy. I don't have any more builds here that were deployed, but if I had some changes I wanted to go back to, you can use the system itself to roll those back to a different state and then also to download them from here too, if in case like someone doesn't have a copy on their, on their system of a different release. So this is very helpful and will become more important over time for helping you to manage. One of the things we get a lot of questions of and might come up later, but this left nav is meant to represent kind of the structure that we see in code. Um, so I'll show the VS Code view in a second again, but this is essentially the project definition, which includes any number of different features. And the first one is an app. And so app, if you think about like this is a tree, projects have what we call top-level components, which are apps, CMS themes. Modules, those things kind of live at this level. And then if I were to have multiple features, those things would be available here and I could navigate between them all from, from this user interface. So that is the first migration that we can look at, but we also have this My First Project app, which is running on platform version 2025.1, which I think a user had mentioned in a in a previous conversation, they have, they tried to migrate to this. So this is a pretty common situation for partners who were building with the first iteration of app cards and they're on this version. And I'm going to show what it looks like now to migrate those to the new platform. And so in that specific instance, I already have a version of that code locally. So I already have a definition for it that I can use. And so I will just run a similar command, hs project migrate instead of app migrate, because we're doing it from inside of the directory for this project. It should understand that this is a project-based app and that it's running an old version and help me navigate to the new version. Oops, that does not come out fully clear. Go up a bit. So you can see here that we have messaging here that show you this is not a reversible process. So once you migrate to any— we introduce breaking changes through the GA releases of the platform. So when you go from one to another, you can't go backwards. So it's important that you consider that nothing is changing about the installs or my customers at this point. It's just the features that I have access to and the development for them that is changing. So It can, it also shows you or displays that we have a couple features here, cards, webhooks, and the app that are going to be converted. So we're going to say yes. And we have to give those things, each of the features, a different UID. So we're going to call this webhooks v1. And cards actually had UIDs when we first introduced them. So the existing cards that were uploaded already have that information. So they're not going to, it's not going to prompt me to input them, but other features that weren't previously available for projects in that version will be asking for the input. So this finished and you can see it was successful. And my local directory changed here in code. So the first thing you'll see is that we actually create an archive of what the previous version was once the migration command is run. So I can go back to this, refer to it in case I have any questions about what was done at the time that I ran the migration command. But going forward, this source directory app is going to be the way that I manage this. So you can see here. My first project out, nothing changed. The only thing that changed is the platform version we're using. You can see that actually this was the, the app name I used. Oh, let me, um, let me make this a little bigger so you can see. So like this was actually the, uh, the app name that we had, old platform version, not probably the best, uh, uh, UID I could have thought of, but I let that kind of play with the defaults and then I have my webhook subscriptions that were already previously defined and my app card, which is written in React here, is also configured. So now from this point on, I can continue to use this and add features. So that's one thing I just wanted to highlight quickly too before we wrap up the demo. So adding features is very straightforward, but you have to do it in accordance with the capabilities of the version that you're running, right? So now that we understand that this project itself and this app are on 2025.2, we get access to new things. And a couple of those new things are setting pages and what we called app homes.
So I'm going to try to paste those in.
So I already built these components or features in the past, so I'm going to just run hs project upload. Now that our local directory has changed, we should see that the build was successfully completed. So all those new components that I have, and if I were to make other changes to the app itself, you can just see that here in the terminal. And you can also see that I need to manually deploy this change, so I have to run the deploy command. And it's asking which build. So this is kind of what I was mentioning before from the user interface. You can specify your deploy, right? Like if I wanted to go back to an earlier build or change that I made in a previous session, I could be, I could do that through the terminal, through the UI. And, um, so we're going to do that one while this is going. I think just to kind of describe that a little bit, it's important for you all to know that it's a two-step process, right? Like you make changes, you upload those changes, and then you have control over when those changes get committed essentially and stored. And then available to customers. And so that's the difference between a build step and a deploy step. I can upload as many times as I want, create new builds, make sure it's working, but only the version of it that I want to go out is the one that I would deploy. And that could be many different numbers, or it could be every single time. And you can configure all that in not only the CLI but also the user interface as well. Something to note there, but Now that that is completed, I can go back to this screen and actually I think I have, oh no, I do not have my customer experience loaded. So I have to navigate to a different account.
Let's see.
So this is a customer of mine. That has the app that I just was changing, upload, or installed. So they have the app installed. And from here, I can now go to and navigate to my first project app. And this is an app homepage. So this is a new feature that we added that takes our UI extensions and allow partners and developers to create their own full page apps, web apps inside of the platform using our component library. So this is something I built for demo. It shows, you know, the checklist of different things that I could do as a user if I wanted to use this for onboarding to my app and different things I had to do along with, you know, table views and other layouts. And then finally analytics and charting. So that is the full migration demo. I'll go back to our slideshow. I think we had a poll. Yep. So I will quickly cover this while you guys answer the, the poll questions and we can cover that and go into Q&A. But, um, what changed with 2025.2? Like, what was the big change from 2025.1 to 2? And it was really these new features that I demonstrated. It was first of all, unifying our entire development process to one configuration, whether it was distributed in the marketplace or whether it was for private consumption. So that's one thing, but then also access to all these other new component features like app homes, app objects, which is really important and powerful. I wish I had time to demo all of that as well. App events likewise, a new way for you to event and timeline, um, kind of activity or engagement that happens externally back into the customer portal. Settings pages, which are fully customizable for you and your customers and what they need for your app. And then agent tools, which is things that you can use for Breeze agents to basically invoke your app through their execution flow. So those are all the new features. I will quickly say we have a lot more coming. So this is what we demonstrated, or we announced at Inbound. We have another release, platform GA release coming up. In a few weeks, so stay tuned for that. A big highlight of that particular release is going to be, you know, serverless functions and our way to kind of help developers that have serverless functions. So you wanna stay tuned for that and we can get started with AMA.
All right, we've got a couple of minutes here, so couple of questions for you, Roger, that came into the Q&A. The, the first one is localhost still allowed as redirect URL in 2025.2 projects? My test app's install link keeps failing with localhost as redirect URL.
Yes, the short answer is yes, it's still allowed. So if it's in your configuration, then it should work. Now the failing side, what local I would get into too much detail here, but like what it's doing is it's trying to reach out to your OAuth backend to try to exchange the code in the install handshake. So whatever you define as the redirect in your app config is where we are going to reach out to, to try to exchange, or you should exchange the token that we grant customer at the install flow to an access and refresh token inside of your database that you need to store and manage that for requests. So it seems like something is probably happening in the locally running OAuth server that you need to have that's running on whatever port you specify in the localhost. Usually the way I would do it if I was running it locally would be specify the port and whatever route is required from the server. And that's most likely what's going on, but.
All right.
Thanks, Roger. I'll get you to the next question is. Not directly linked, but when developing apps for specific big individual customers, clients, what's the best approach to build and deploy to multiple environments? Example, their sandbox and live portal.
Yeah, so we offer two approaches to this problem, and it's really up to you to decide which one makes the most sense. We try to provide a little bit more out-of-the-box handling with something we call profiles. Which allowed you to use the same app configuration in one instance to deploy to different installs. Like whether that is like a modification that you want to make in a QA version of your app or a sandbox environment for a customer, that's a profile in the configuration that you can include inside of the project itself that manages basically the number of apps that exist and some of the, the differences in those configurations across different installs of it. The other option is obviously creating multiple app instances that you have to manually manage the code differences between. But since it's all controlled, like in a remote repository, you can merge changes and use branches, branches and CI process or other ways to deploy changes in a specific environment for testing and confirmation before they get promoted to the production environment. So I think moving to code-based functionality like we have for the CLI allows a lot more customization and flexibility depending on what your development lifecycle looks like. We have time for one more.
We've time for one more, and it's more related to our documentation. So apart from our latest documentation, is there a place we could check the old documentation? For example, Projects version 2025.1. So we can debug old projects.
Short answer is yes. All of the documentation that was on the old site before we migrated to the new one as part of our announcement inbound, the new developer platform was translated into that new site. So any, any existing documentation should already be there. And going forward, one of the things that we are going to introduce more, which, you know, we only have like really one major release at the moment. So this is going to become more of a thing, but you will be able to actually look at different versions of the documentation based on the platform itself. So like you'll be able to see how a component changes over time based on the specified version that you get to choose in the documentation site. So it will be much easier to kind of navigate those things. You can have them side by side and that sort of thing.
I'm going to sneak one more question in here as we get done, because I think it's a really important one here, Roger. Are there any deadlines for upgrading a public legacy app to 2025.2? And I'm happy to help you on this one too.
Why don't you go first and I'll fill in any gaps?
That's totally fine. We don't have any hard deadlines when it means to go to 2025.2, but we highly encourage it because this is, as we move forward and we have new versions of projects released, it's where our best functionality is going to live and old legacy feature functionalities are not necessarily necessarily going to be compatible with those always going forward. So we highly encourage it. It will then be the base for your apps functioning at top quality, best value to your customers, and continued new feature functionality that you can offer.
Good answer. Yeah, I would, I would say, but it's, it's, it's really up to you to decide. We don't have any explicit deadlines for the migration, but I think there's a lot of benefits to doing so. And really no downside. The only difference to you as a developer is the way that you manage those changes, essentially moving from the user interface to projects and the CLI, right, that I demonstrated. That's really the only downside, or it's an upside for, I think, most of our ecosystem. And then you get access to a whole lot more.
All right.
Thanks all for tuning in. Thanks, Roger, for two great sessions. Everyone is welcome to then move along to our next session where you'll learn a little bit more about our marketplace. Thanks all.










