Docs
Migration Guide (v1 → v2)

Migration Guide: v1 → v2

This guide covers the breaking changes in Stackflow 2.0 and how to migrate from v1.

Overview

Stackflow 2.0 introduces a config-first approach that separates activity declarations from React components. This enables better performance through framework-agnostic loading and improved type safety.

Step 1: Install @stackflow/config

npm install @stackflow/config

Step 2: Create stackflow.config.ts

Extract your activity declarations into a config file.

Before:

stackflow.ts
import { stackflow } from "@stackflow/react";
 
export const { Stack, useFlow } = stackflow({
  transitionDuration: 350,
  activities: {
    HomeActivity,
    MyProfileActivity,
  },
  plugins: [],
});

After:

stackflow.config.ts
import { defineConfig } from "@stackflow/config";
 
export const config = defineConfig({
  activities: [
    { name: "HomeActivity" },
    { name: "MyProfileActivity" },
  ],
  transitionDuration: 350,
});
stackflow.ts
import { stackflow } from "@stackflow/react";
import { config } from "./stackflow.config";
 
export const { Stack, useFlow } = stackflow({
  config,
  components: {
    HomeActivity,
    MyProfileActivity,
  },
  plugins: [],
});

Step 3: Update historySyncPlugin

Routes are now declared in stackflow.config.ts instead of the plugin options.

Before:

historySyncPlugin({
  routes: {
    HomeActivity: "/",
    MyProfileActivity: "/my-profile",
  },
  fallbackActivity: () => "HomeActivity",
})

After:

In stackflow.config.ts:

defineConfig({
  activities: [
    { name: "HomeActivity", route: "/" },
    { name: "MyProfileActivity", route: "/my-profile" },
  ],
})

In stackflow.ts:

historySyncPlugin({
  config,
  fallbackActivity: () => "HomeActivity",
})

Step 4: Update Activity Types

Types are now registered via module augmentation instead of component Props.

Before:

Article.tsx
import type { ActivityComponentType } from "@stackflow/react";
 
type ArticleParams = {
  title: string;
};
 
const Article: ActivityComponentType<ArticleParams> = ({ params }) => {
  // ...
};

After:

Article.tsx
import type { ActivityComponentType } from "@stackflow/react";
 
declare module "@stackflow/config" {
  interface Register {
    Article: {
      title: string;
    };
  }
}
 
const Article: ActivityComponentType<"Article"> = ({ params }) => {
  // params.title is typed
};

Step 5: Update useFlow and useStepFlow Imports

Hooks are now imported directly from @stackflow/react instead of being created from a factory function.

Before:

import { useFlow } from "./stackflow"; // from your stackflow.ts

After:

import { useFlow } from "@stackflow/react"; // direct import

Step 6: Rename useStepFlow Functions

The step navigation function names have changed.

BeforeAfter
stepPush()pushStep()
stepReplace()replaceStep()
stepPop()popStep()

Step 7: Update <Link /> Import

The <Link /> component is now imported directly.

Before:

Link.ts
import { createLinkComponent } from "@stackflow/link";
import type { TypeActivities } from "./stackflow";
 
export const { Link } = createLinkComponent<TypeActivities>();

After:

import { Link } from "@stackflow/link";

Step 8: Update Import Paths

Replace all occurrences of the old entry points.

BeforeAfter
@stackflow/react/future@stackflow/react
@stackflow/link/future@stackflow/link

Removed Packages

The following packages have been removed in v2:

  • @stackflow/plugin-preload — Use the built-in Loader API instead. See Preloading.
  • @stackflow/plugin-map-initial-activity — Use initialActivity in defineConfig() instead.

API Correspondence Table

v1v2
stackflow({ transitionDuration, activities, plugins })stackflow({ config, components, plugins })
ActivityComponentType<Params>ActivityComponentType<"ActivityName">
useFlow() from ./stackflowuseFlow() from @stackflow/react
useStepFlow() from ./stackflowuseStepFlow() from @stackflow/react
stepPush/stepReplace/stepPoppushStep/replaceStep/popStep
createLinkComponent<TypeActivities>()import { Link } from "@stackflow/link"
historySyncPlugin({ routes, fallbackActivity })historySyncPlugin({ config, fallbackActivity })
preloadPlugin(...)Built-in Loader API