Migration
Migrate to Robo.js from other setups
Migration from an existing Discord Activity project to Robo.js.
Side-by-side comparison of a plain Embedded App SDK project structure on the left versus a Robo.js activity project on the right, showing file reorganization
From Plain Embedded App SDK
Robo.js adds file-based routing (your file names and folder structure automatically become commands/endpoints), a plugin system, built-in tunnels, and development tools on top of the Embedded App SDK. To migrate:
- Create a new Robo project:
npx create-robo my-activity - Move frontend code to
src/app/ - Move backend code to
src/api/ - Use the
useDiscordSdkhook or keep manual SDK initialization - Move environment variables to
.env
Before and After: SDK Initialization
Before (plain SDK):
import { DiscordSDK } from '@discord/embedded-app-sdk'
const sdk = new DiscordSDK(CLIENT_ID)
await sdk.ready()
const { code } = await sdk.commands.authorize({ client_id: CLIENT_ID, response_type: 'code', scope: ['identify'] })
// manual token exchange...import { DiscordSDK } from '@discord/embedded-app-sdk'
const sdk = new DiscordSDK(CLIENT_ID)
await sdk.ready()
const { code } = await sdk.commands.authorize({ client_id: CLIENT_ID, response_type: 'code', scope: ['identify'] })
// manual token exchange...After (Robo.js):
import { DiscordContextProvider } from '../hooks/useDiscordSdk'
import { Activity } from './Activity'
export default function App() {
return (
<DiscordContextProvider authenticate scope={['identify', 'guilds']}>
<Activity />
</DiscordContextProvider>
)
}import { DiscordContextProvider } from '../hooks/useDiscordSdk'
import { Activity } from './Activity'
export default function App() {
return (
<DiscordContextProvider authenticate scope={['identify', 'guilds']}>
<Activity />
</DiscordContextProvider>
)
}The DiscordContextProvider handles SDK initialization, authorization, token exchange, and authentication automatically.
Code comparison showing manual DiscordSDK setup with explicit ready(), authorize(), authenticate() calls versus the DiscordContextProvider wrapper approach
From Next.js
- Create a Robo activity project:
npx create-robo my-activity - Move page components from
pages/orapp/tosrc/app/ - Convert API routes from
pages/api/orapp/api/tosrc/api/(changeNextApiRequest/NextApiResponsetoRoboRequest) - Move static assets from
public/topublic/ - Update imports — Robo uses
.jsextensions in import paths (e.g.,import { foo } from './bar.js') - Move environment variables from
.env.localto.env
From Create React App (CRA)
- Create a Robo activity project:
npx create-robo my-activity - Move components from
src/tosrc/app/ - Move
public/assets topublic/ - Replace
react-scriptswithnpx robo dev/npx robo build - Update imports to use
.jsextensions
From Express or Fastify Backend
Convert routes to the file-based src/api/ structure. Each route file exports a default handler function.
import type { RoboRequest } from '@robojs/server'
export default (req: RoboRequest) => {
return { status: 'ok' }
}export default (req) => {
return { status: 'ok' }
}For Fastify, the @robojs/server plugin supports custom engine configuration.
Common Pitfalls
| Issue | Solution |
|---|---|
Missing .js extensions | Robo.js requires .js extensions in import paths, even for TypeScript files. Add them to all relative imports. |
.env not loading | Ensure .env is in the project root (not in src/ or a subdirectory). Robo.js loads it automatically. |
| Files in wrong directory | Frontend code goes in src/app/, not src/. API routes go in src/api/. |
| Vite config missing | Activity projects need config/vite.mjs with DiscordProxy.Vite() in the plugins array. |
