> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runloop.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Share a Live Preview

> Start your app and share a live preview link in pull requests using devbox tunnels.

<Tip>This is an optional extension of the [Running Agents on Sandboxes](/docs/tutorials/running-agents-on-sandboxes) tutorial. Complete the main tutorial first.</Tip>

<Note title="Starter image">
  The starter image is used when you start a devbox without specifying an image, and as the default base when you build a blueprint without providing Dockerfile content. It includes:

  * **Core tools:** jq, sudo
  * **Extras:** dnsutils, iputils-ping, less, vim, rsync,
    gh
  * **Python stack:** Python 3.12, pip, uv
  * **Node stack:** Node 22.15.0, npm, Yarn 1.22.22 via
    corepack
</Note>

## Overview

Instead of just pushing code changes, you can start a Next.js development server and create a tunnel to share a live preview link in your pull request. This allows reviewers to see the changes in action before merging.

<Steps>
  <Step title="Install dependencies and start the dev server">
    Install the project dependencies and start a Next.js development server. Make sure to bind to `0.0.0.0` so the tunnel can access it from outside the devbox.

    <CodeGroup>
      ```python Python theme={null}
      # Create a named shell and navigate to the project directory
      shell = devbox.shell("preview-shell")
      await shell.exec("cd ~/sample-todo-nextjs")

      # Install dependencies
      await shell.exec("npm install")

      # Start the Next.js dev server in the background
      server_command = await shell.exec_async(
        "HOSTNAME=0.0.0.0 npm run dev"
      )
      print("Next.js dev server started")
      ```

      ```typescript TypeScript theme={null}
      // Create a named shell and navigate to the project directory
      const shell = devbox.shell('preview-shell');
      await shell.exec('cd ~/sample-todo-nextjs');

      // Install dependencies
      await shell.exec('npm install');

      // Start the Next.js dev server in the background
      const serverCommand = await shell.execAsync(
        'HOSTNAME=0.0.0.0 npm run dev'
      );
      console.log('Next.js dev server started');
      ```
    </CodeGroup>
  </Step>

  <Step title="Enable a tunnel to the dev server">
    Enable a tunnel on the Devbox to access port 3000 where the Next.js dev server is running. This will give you a public URL that you can share.

    <CodeGroup>
      ```python Python theme={null}
      # Enable a tunnel on the devbox
      await devbox.net.enable_tunnel(auth_mode="open")

      # Get the preview URL for port 3000
      preview_url = await devbox.get_tunnel_url(3000)
      print(f"Live preview URL: {preview_url}")
      ```

      ```typescript TypeScript theme={null}
      // Enable a tunnel on the devbox
      await devbox.net.enableTunnel({ auth_mode: "open" });

      // Get the preview URL for port 3000
      const previewUrl = await devbox.getTunnelUrl(3000);
      console.log(`Live preview URL: ${previewUrl}`);
      ```
    </CodeGroup>
  </Step>

  <Step title="Post the preview link to the PR">
    Post the preview URL as a comment on your pull request so reviewers can view the changes live.

    <CodeGroup>
      ```python Python theme={null}
      import os
      from github import Github  # Requires PyGithub library

      # Initialize GitHub client
      g = Github(os.environ["GH_TOKEN"])
      repo = g.get_repo("runloopai/sample-todo-nextjs")
      pr = repo.get_pull(pr_number)

      # Post the preview link as a comment
      comment = f"🚀 Live preview of changes: {preview_url}\n\nYou can view the updated color scheme in action at the link above."
      pr.create_issue_comment(comment)
      print(f"Posted preview link to PR #{pr_number}")
      ```

      ```typescript TypeScript theme={null}
      import { Octokit } from '@octokit/rest';

      // Initialize GitHub client
      const octokit = new Octokit({ auth: process.env.GH_TOKEN });

      // Post the preview link as a comment
      const comment = `🚀 Live preview of changes: ${previewUrl}\n\nYou can view the updated color scheme in action at the link above.`;
      await octokit.rest.issues.createComment({
        owner: 'runloopai',
        repo: 'sample-todo-nextjs',
        issue_number: prNumber,
        body: comment,
      });
      console.log(`Posted preview link to PR #${prNumber}`);
      ```
    </CodeGroup>

    <Note>
      The tunnel URL will remain active as long as the devbox is running. Reviewers can click the link to see your changes in real-time. If you suspend the devbox, the tunnel will be unavailable until you resume it and re-enable the tunnel.
    </Note>
  </Step>
</Steps>

## Next Steps

* Learn how to [suspend and resume your devbox](/docs/tutorials/running-agents-on-sandboxes/suspend-resume-workflow) for iterative PR feedback
* Explore [devbox tunnels](/docs/devboxes/tunnels) for more advanced networking scenarios
