Upgrade from v1 to v2
This guide walks you through upgrading an existing Next.js App Router project from Uniform SDK v1 (@uniformdev/canvas-next-rsc) to v2 (@uniformdev/next-app-router). The v2 SDK requires Next.js 16 and introduces a new middleware-based architecture, a new file structure, and updated component APIs.
warning
This guide is for customers who are already using the App Router with the earlier Uniform SDK packages (@uniformdev/canvas-next-rsc, @uniformdev/canvas-react, etc.) and want to upgrade to the v2 SDK. If you are migrating from the Page Router to the App Router, contact support for assistance.
Overview of changes#
| Area | v1 | v2 |
|---|---|---|
| Main package | @uniformdev/canvas-next-rsc + several others | @uniformdev/next-app-router (single package) |
| Middleware | Optional | Required |
| File structure | app/[[...slug]]/page.tsx (catch-all) | app/uniform/[code]/page.tsx |
| Component props | Parameters flattened to top-level | Parameters in a parameters object with ComponentParameter<T> wrappers |
| Slots | <UniformSlot name="slotName" /> | <UniformSlot slot={slots.slotName} /> |
| Server config | Required (uniform.server.config.ts) | Optional (sensible defaults) |
| Route client | getDefaultRouteClient | getRouteClient |
Step 1: Update packages#
Remove the old v1 packages and install the new v2 package:
Your package.json should include:
note
It's best to reference @uniformdev/next-app-router in your package.json to avoid version mismatches as new packages are released.
Step 2: Add middleware#
Middleware is now required to route requests and evaluate compositions. Create middleware.ts in your project root:
Why middleware.ts instead of proxy.ts?
This recipe uses middleware at the project root rather than a proxy-based setup. It is a workaround for a current Next.js limitation: draft mode is not accurate in middleware when using the Node.js runtime (e.g. in a proxy). Using middleware.ts with the edge runtime avoids this, so Uniform preview and draft mode work correctly.
Custom rewrites (optional)#
If you need to code-split your components and avoid defining them all on every page, you can customize where the middleware rewrites to:
Step 3: Update file structure#
The catch-all route pattern has changed. Replace your old app/[[...slug]]/page.tsx with the new structure:
Before (v1):
After (v2):
Main composition page#
Create app/uniform/[code]/page.tsx:
Playground page#
Create app/playground/[code]/page.tsx:
Step 4: Update server config (optional)#
If you have a uniform.server.config.ts or uniform.server.config.js, you can remove it if it matches the following defaults:
If your config differs from the defaults, keep the file and update the import path from the old package to @uniformdev/next-app-router/config.
Step 5: Update component props#
The ComponentProps type has been reworked. The two key changes are:
- Parameters are no longer spread to the top level -- they are now in a
parametersobject. - Parameter values are wrapped in
ComponentParameter<T>-- access the value with.value.
Before (v1)#
After (v2)#
Full v2 ComponentProps type#
For reference, the full v2 ComponentProps type is:
Key differences from v1:
- You are no longer passed the entire component instance directly -- use the
component(ComponentContext) object instead. - The
slotNameandslotIndexproperties have been removed from the top level.
Step 6: Update slots#
Slots are now passed as objects in the slots prop rather than being rendered by name.
Before (v1)#
After (v2)#
Accessing slot items programmatically#
If you need to extract the rendered components from a slot:
Step 7: Update client helpers#
The route client function has been renamed:
| v1 | v2 |
|---|---|
getDefaultRouteClient | getRouteClient |
Update any code that references the old function name.
Step 8: Use the adapter layer (optional)#
If you have many components and want to migrate incrementally, the v2 SDK provides an adapter layer that lets you use v1-style component definitions alongside v2 components.
Set up the adapter resolver#
Adapt individual components#
Add mode: 'adapted' to each component mapping that you haven't fully migrated yet:
When using the adapter layer, use UniformText and UniformSlot from the compat export:
This allows you to migrate components one at a time from the adapted (v1-style) API to the native v2 API.
Migration checklist#
Use this checklist to track your progress:
[ ] Install
@uniformdev/next-app-routerand remove old packages[ ] Add
middleware.tswithuniformMiddleware()[ ] Move from
app/[[...slug]]/page.tsxtoapp/uniform/[code]/page.tsx[ ] Add
app/playground/[code]/page.tsx[ ] Update or remove
uniform.server.config.ts[ ] Update
ComponentPropsto useparametersobject andComponentParameter<T>[ ] Update
UniformSlotfromnameprop toslotprop[ ] Rename
getDefaultRouteClienttogetRouteClient[ ] Update
next.config.tsto usewithUniformConfig[ ] Test visual editing in the Uniform dashboard
[ ] Test personalization and A/B testing