Tasks
The Tasks API allows you to manage and run predefined commands in your sandbox. Tasks are typically defined in your project's configuration and can include development servers, build processes, tests, or any other command-line operations.
We might still change the Task API in the future to make it better suited for the SDK, let us know if you have any feedback or suggestions!
Configuration
Tasks are configured in your project's .codesandbox/tasks.json
file. This file defines both setup tasks that run when the sandbox starts, and regular tasks that can be run on-demand.
Setup Tasks
Setup tasks run in order when initializing your sandbox. They're typically used for installation and preparation steps:
{
"setupTasks": [
{
"name": "Install Dependencies",
"command": "pnpm install"
},
{
"name": "Copy Environment File",
"command": "cp .env.example .env"
},
"pnpm run build" // Short form for { "name": "pnpm run build", "command": "pnpm run build" }
]
}
Regular Tasks
Regular tasks can be run at any time and support more configuration options:
{
"tasks": {
"dev": {
"name": "Development Server",
"command": "pnpm dev",
"runAtStart": true,
"preview": {
"port": 3000
},
"restartOn": {
"files": ["package.json", "pnpm-lock.yaml"], // Restart when package.json or pnpm-lock.yaml changes
"clone": true, // Restart right after this VM was cloned from another VM
"resume": false // Restart when sandbox resumes from hibernation
}
},
"build": {
"name": "Production Build",
"command": "pnpm build",
"preview": {
"port": 4000
}
},
"test": {
"name": "Run Tests",
"command": "pnpm test",
"restartOn": {
"files": ["tests/**/*"]
}
}
}
}
Task Options
Each task can have the following options:
name
: Display name for the taskcommand
: The command to executerunAtStart
: Whether to run the task when the sandbox startspreview
: Configuration for task previewport
: Port number to preview
restartOn
: Configure when the task should restartfiles
: Array of file patterns that trigger restart when changedclone
: Restart when this VM was cloned from another VMresume
: Restart when sandbox resumes from hibernation
Example Configuration
Here's a more complete example showing various task configurations:
{
"setupTasks": [
{
"name": "Install Dependencies",
"command": "pnpm install"
},
{
"name": "Copy Environment",
"command": "cp .env.example .env.local"
}
],
"tasks": {
"dev": {
"name": "Development",
"command": "pnpm dev",
"runAtStart": true,
"preview": {
"port": 3000,
"prLink": "direct"
},
"restartOn": {
"files": ["package.json", ".env.local"],
"branch": false,
"resume": false
}
},
"storybook": {
"name": "Storybook",
"command": "pnpm storybook",
"preview": {
"port": 6006
}
},
"test:watch": {
"name": "Test Watch",
"command": "pnpm test:watch",
"restartOn": {
"files": ["tests/**/*", "src/**/*.test.*"]
}
},
"typecheck": {
"name": "Type Check",
"command": "pnpm typecheck"
},
"lint:fix": {
"name": "Fix Lint Issues",
"command": "pnpm lint --fix"
}
}
}
Setup Tasks
Setup tasks run automatically when a sandbox starts. They typically handle installation of dependencies and initial builds. You can monitor and control setup tasks using the Setup API:
const sandbox = await sdk.sandbox.create();
// Listen to setup progress
sandbox.setup.onSetupProgressUpdate((progress) => {
console.log(`Setup progress: ${progress.currentStepIndex + 1}/${progress.steps.length}`);
console.log(`Current step: ${progress.steps[progress.currentStepIndex].name}`);
});
// Get current progress
const progress = await sandbox.setup.getProgress();
console.log(`Setup state: ${progress.state}`);
// Wait for setup to finish
const result = await sandbox.setup.waitForFinish();
if (result.state === "FINISHED") {
console.log("Setup completed successfully");
}
Setup Tasks vs Docker Build: When to Use Which?
Setup tasks are used for any preparation work needed in the /project/sandbox
directory, such as:
- Installing dependencies
- Building assets
- Running initial compilations
Docker build, on the other hand, should be used for:
- Setting up the container environment
- Installing system-level dependencies
- Configuring global tools
This separation exists because the /project/sandbox
directory is only available after the container starts.
Setup Progress
The setup progress includes the following information:
type SetupProgress = {
state: "IDLE" | "IN_PROGRESS" | "FINISHED" | "STOPPED";
steps: {
name: string;
command: string;
shellId: string | null;
finishStatus: "SUCCEEDED" | "FAILED" | "SKIPPED" | null;
}[];
currentStepIndex: number;
};
Tasks
The Tasks API is available under sandbox.tasks
. It provides methods for listing, retrieving, and running tasks in your sandbox.
Regular tasks are defined in the tasks
section of your tasks.json
file. Each task has a unique ID and can be configured to run automatically when the sandbox starts by setting runAtStart: true
. They will start after setup has completed.
Listing Tasks
You can get all available tasks in your sandbox:
const sandbox = await sdk.sandbox.create();
// Get all tasks
const tasks = await sandbox.tasks.getTasks();
for (const task of tasks) {
console.log(`Task: ${task.name} (${task.command})`);
}
Running Tasks
You can run a task using its ID:
const sandbox = await sdk.sandbox.create();
// Run a specific task
const task = await sandbox.tasks.runTask("dev");
console.log(`Started task: ${task.name}`);
// If the task opens a port, you can access it
if (task.ports.length > 0) {
const port = task.ports[0];
console.log(`Preview available at: ${port.getPreviewUrl()}`);
}
Getting Task Information
You can get information about a specific task:
const sandbox = await sdk.sandbox.create();
// Get a specific task
const task = await sandbox.tasks.getTask("build");
if (task) {
console.log(`Task: ${task.name}`);
console.log(`Command: ${task.command}`);
console.log(`Runs at start: ${task.runAtStart}`);
if (task.shellId) {
console.log("Task is currently running");
}
}
Examples
Starting a Development Server
Here's an example of running a development server task and waiting for it to be ready:
const sandbox = await sdk.sandbox.create();
// Get the dev task
const task = await sandbox.tasks.getTask("dev");
if (!task) {
throw new Error("Dev task not found");
}
// Run the task
await sandbox.tasks.runTask(task.id);
// If the task has a preview port configured
if (task.preview?.port) {
// Wait for the port to open
const portInfo = await sandbox.ports.waitForPort(task.preview.port);
console.log(`Dev server ready at: ${portInfo.getPreviewUrl()}`);
}
Running Multiple Tasks
You can run multiple tasks and monitor their ports:
const sandbox = await sdk.sandbox.create();
// Get all tasks that should run at start
const tasks = await sandbox.tasks.getTasks();
// Run all startup tasks
for (const task of tasks) {
console.log(`Starting ${task.name}...`);
sandbox.tasks.runTask(task.id);
}
// Monitor ports for all tasks
sandbox.ports.onDidPortOpen((portInfo) => {
const task = tasks.find(t =>
t.preview?.port === portInfo.port
);
if (task) {
console.log(`${task.name} is ready at: ${portInfo.getPreviewUrl()}`);
}
});