Skip to main content

Preview Environments

Preview environments let you run multiple services in a cloud container with automatic domain routing. Each port you configure gets a unique public URL, and environment variables are injected so your applications can communicate with each other.

Overview

When you spawn an environment, Roo Code Cloud:

  1. Creates a cloud container with your configured ports exposed
  2. Generates unique HTTPS domains for each port
  3. Injects environment variables like ROO_WEB_HOST and ROO_API_HOST into your container
  4. Clones your repositories, starts services, and runs your commands

This allows you to run a complete stack—frontend, API, workers—in a single preview environment where all the pieces can talk to each other.

Configuration

Environments are configured in YAML format. Here's the complete schema:

name: My Full Stack App
description: Frontend and API running together

repositories:
- repository: myorg/frontend
commands:
- name: Install
run: npm install
- name: Start
run: npm run dev
detached: true

- repository: myorg/backend
commands:
- name: Install
run: npm install
- name: Start
run: npm run dev
detached: true

ports:
- name: WEB
port: 3000
- name: API
port: 3001

services:
- postgres16
- redis7

env:
NODE_ENV: development

Named Ports

The ports section defines which ports to expose and what to call them:

ports:
- name: WEB
port: 3000
- name: API
port: 3001
- name: ADMIN
port: 3002

For each named port, an environment variable is injected into your container:

Port ConfigEnvironment VariableExample Value
name: WEB, port: 3000ROO_WEB_HOSThttps://abc123.vercel.run
name: API, port: 3001ROO_API_HOSThttps://def456.vercel.run
name: ADMIN, port: 3002ROO_ADMIN_HOSThttps://ghi789.vercel.run

Naming Rules

Port names must:

  • Start with a letter
  • Contain only letters, numbers, and underscores
  • Be 1-50 characters long

The name is converted to uppercase for the environment variable (e.g., web becomes ROO_WEB_HOST).

Limits

You can configure up to 4 named ports per environment.

Using Environment Variables in Your Code

Use the ROO_<NAME>_HOST variables instead of hardcoded URLs so your services can find each other in both preview and local environments:

// Backend: configure CORS with the injected frontend URL
app.use(cors({
origin: process.env.ROO_WEB_HOST || 'http://localhost:3000'
}));

// Frontend (Vite): pass the API URL at build time
// vite.config.ts
export default defineConfig({
define: {
'import.meta.env.API_URL': JSON.stringify(process.env.ROO_API_HOST || 'http://localhost:3001')
}
})

For static site frameworks (Vite, Next.js, CRA), the API URL needs to be set at build time via command-level env:

commands:
- name: Build
run: npm run build
env:
VITE_API_URL: ${ROO_API_HOST}

Repositories

List the repositories to clone into your environment:

repositories:
- repository: myorg/frontend
commands:
- name: Install dependencies
run: npm install
- name: Build
run: npm run build
- name: Start dev server
run: npm run dev
detached: true
logfile: /tmp/frontend.log

- repository: myorg/backend
commands:
- name: Install dependencies
run: npm install
- name: Run migrations
run: npm run db:migrate
- name: Start server
run: npm run start
detached: true
logfile: /tmp/backend.log

Repository Format

Use the owner/repo format (e.g., myorg/my-app).

Commands

Each repository can have its own commands that run in order. Commands support:

FieldDescriptionDefault
nameDisplay name for the commandRequired
runThe shell command to executeRequired
working_dirRelative directory to run the command inRepository root
cwdAbsolute path to run the command inRepository root
envCommand-specific environment variablesNone
timeoutMaximum seconds to wait60
continue_on_errorKeep going if command failsfalse
detachedRun in the background (see below)false
logfileFile path to write stdout/stderr when detached is trueNone

Background Processes

To start a long-running process like a dev server, use detached: true. This runs the command in the background so subsequent commands can execute immediately:

commands:
- name: Install
run: npm install
- name: Start dev server
run: npm run dev
detached: true
logfile: /tmp/dev-server.log

When detached is true, the command runs via nohup and the worker moves on after confirming the process started. If logfile is set, stdout and stderr are written to that path — useful for debugging startup issues.

Automatic Tool Installation

If a repository contains a .tool-versions file (used by mise / asdf), Roo Code Cloud automatically runs mise install after cloning. This installs the correct versions of tools like Node.js, Python, Ruby, Go, or any other runtime your project requires — before any of your setup commands execute.

# .tool-versions
nodejs 20.11.0
python 3.12.1

Services

Add managed database and cache services:

services:
- redis7
- postgres16

Available Services

ServiceDefault PortConnection Variables
redis66379REDIS_URL
redis76379REDIS_URL
postgres155432DATABASE_URL, POSTGRES_*
postgres165432DATABASE_URL, POSTGRES_*
postgres175432DATABASE_URL, POSTGRES_*
mysql83306DATABASE_URL, MYSQL_*
mariadb103306DATABASE_URL, MARIADB_*
clickhouse9000CLICKHOUSE_URL

Custom Ports

If you need a service on a non-default port:

services:
- name: postgres16
port: 5433

Environment Variables

Define environment variables available to all commands:

env:
NODE_ENV: development
LOG_LEVEL: debug
FEATURE_FLAGS: "new-ui,beta-api"

These are merged with:

  1. Service connection variables (e.g., DATABASE_URL)
  2. Named port variables (e.g., ROO_WEB_HOST)
  3. Command-specific variables (highest priority)

Complete Example

Here's a full-stack application with a React frontend, Hono API, and background worker:

name: E-Commerce Platform
description: Full stack with frontend, API, and worker

repositories:
- repository: acme/storefront
commands:
- name: Install
run: npm install
- name: Build
run: npm run build
env:
VITE_API_URL: ${ROO_API_HOST}
- name: Serve
run: npx serve -s dist -l 3000
detached: true
logfile: /tmp/storefront.log

- repository: acme/api
commands:
- name: Install
run: npm install
- name: Migrate
run: npm run db:push
- name: Start
run: npm run start
detached: true
logfile: /tmp/api.log
env:
ALLOWED_ORIGINS: ${ROO_WEB_HOST}

- repository: acme/worker
commands:
- name: Install
run: npm install
- name: Start
run: npm run start
detached: true
logfile: /tmp/worker.log

ports:
- name: WEB
port: 3000
- name: API
port: 3001
- name: WORKER
port: 3002

services:
- postgres16
- redis7

env:
NODE_ENV: production
LOG_LEVEL: info

After the environment starts, you'll get unique URLs for each port. Visit the WEB URL to access your running application.

Common Issues

CORS Errors

In a preview environment, your frontend and backend run on different domains (e.g., https://abc123.vercel.run and https://def456.vercel.run). Browsers block cross-origin requests by default, so your backend needs to explicitly allow the frontend's domain.

Use the ROO_WEB_HOST variable to configure your backend's CORS policy:

Express:

import cors from 'cors';

app.use(cors({
origin: process.env.ROO_WEB_HOST || 'http://localhost:3000'
}));

Hono:

import { cors } from 'hono/cors';

app.use(cors({
origin: process.env.ROO_WEB_HOST || 'http://localhost:3000'
}));

Fastify:

app.register(import('@fastify/cors'), {
origin: process.env.ROO_WEB_HOST || 'http://localhost:3000'
});

Then in your environment config, make sure both ports are defined so the variables get injected:

ports:
- name: WEB
port: 3000
- name: API
port: 3001

Managing Frontend API URLs with .env Files

Frontends typically need the API URL at build time. If your project already uses .env files (via dotenv, dotenvx, or framework built-ins like Vite's .env.local), you can write the injected ROO_API_HOST into a .env file as a setup command — no code changes needed:

repositories:
- repository: myorg/frontend
commands:
- name: Configure API URL
run: echo "VITE_API_URL=${ROO_API_HOST}" >> .env.local
- name: Install
run: npm install
- name: Start
run: npm run dev
detached: true

This works with any framework that reads .env files:

FrameworkFileVariable prefix
Vite.env.localVITE_
Next.js.env.localNEXT_PUBLIC_
Create React App.env.localREACT_APP_

This approach keeps your environment config simple and avoids modifying application code.

Tips

  • Use ROO_*_HOST variables, not hardcoded URLs. Always fall back to localhost for local dev: process.env.ROO_API_HOST || 'http://localhost:3001'.
  • Use consistent uppercase port names. WEB, API, ADMIN — not frontend, BACKEND_API, Admin_Panel.