LogoFreestyle

Run a Dev Server

Use a git repo and dev server to create a hot reload environment.

Dev Servers are instant development and preview environments for your Git Repositories.

They come with everything you need to show a live preview to your users, while giving your agents the ability to work with the code.

Dev Servers on Freestyle Dev Servers:

  • Automatically keep npm run dev alive — if it crashes we detect that and restart it.
  • An MCP server that makes connecting your agents to the dev server easy.
  • A managed Git Identity for your dev server, so it can push/pull code from the repo.

Special Features:

  • VSCode Web Interface accessible for human collaboration on dev servers.
  • Chromium + Playwright setup for testing

Coming Soon:

  • VSCode Server Interface to open Dev Servers in VSCode and Chromium
  • VSCode Language Server Interface to run LSP commands (which the MCP will have access to)

Creating a Dev Server

In order to create a dev server, you'll need a Git Repository to base it on.

import { FreestyleSandboxes } from "freestyle-sandboxes";

const freestyle = new FreestyleSandboxes();


const { repoId } = await freestyle.createGitRepository({
  name: "Test Repository",

  // This will make it easy for us to clone the repo during testing.
  // The repo won't be listed on any public registry, but anybody
  // with the uuid can clone it. You should disable this in production.
  public: true,

  source: {
    url: "https://github.com/freestyle-sh/freestyle-next",
    type: "git",
  },
});

console.log(`Created repo with ID: ${repoId}`);
import freestyle

client = freestyle.Freestyle("YOUR_FREESTYLE_API_KEY")

repo = client.create_repository(
  name="Test Repository from Python SDK",


  # This will make it easy for us to clone the repo during testing.
  # The repo won't be listed on any public registry, but anybody
  # with the uuid can clone it. You should disable this in production.
  public=True,
  source=freestyle.CreateRepoSource.from_dict(
      {
          "type": "git",
          "url": "https://github.com/freestyle-sh/freestyle-base-nextjs-shadcn",
      }
  ),
)

print(f"Created repo with ID: {repo.repo_id}")

Then, you can request a dev server for the repo you just created.

import { FreestyleSandboxes } from "freestyle-sandboxes";

const freestyle = new FreestyleSandboxes();

const devServer = await freestyle.requestDevServer({ repoId });

console.log(`Dev Server URL: ${devServer.ephemeralUrl}`);
import freestyle

client = freestyle.Freestyle("YOUR_FREESTYLE_API_KEY")

dev_server = client.request_dev_server(repo_id=repo.repo_id)

print(f"Dev Server URL: {dev_server.ephemeral_url}")

This will give you a dev server that is automatically running npm run dev. If you don't keep it alive, it will shut itself down.

Working with Dev Servers

When you run a dev server, you get access to the following utilities:

const {
  ephemeralUrl, // URL to the dev server, shows whatever server the dev server is running
  mcpEphemeralUrl, // URL to the MCP server, which lets your AI Agents interact with the dev server
  codeServerUrl, // URL to the VSCode Web Interface

  commitAndPush, // Function to commit and push whatever is on the dev server now to the repo
  fs, // File system interface to the dev server
  process, // Process interface to the dev server to run commands

  isNew, // Boolean indicating if the dev server was just created
  shutdown, // Shutdown handle to stop the dev server

} = await freestyle.requestDevServer({
repoId: repoId,
});
dev_server = client.request_dev_server(
    repo_id=repo.repo_id,
)

ephemeral_url = dev_server.ephemeral_url # URL to the dev server, shows whatever server the dev server is running
mcp_ephemeral_url = dev_server.mcp_ephemeral_url # URL to the MCP server, which lets your AI Agents interact with the dev server
code_server_url = dev_server.code_server_url # URL to the VSCode Web Interface

commit_and_push = dev_server.commit_and_push # Function to commit and push whatever is on the dev server now to the repo
fs = dev_server.fs # File system interface to the dev server
process = dev_server.process # Process interface to the dev server to run commands

is_new = dev_server.is_new # Boolean indicating if the dev server was just created
shutdown = dev_server.shutdown # Shutdown handle to stop the dev server

The URLs

Dev Servers provide a series of URLs that you can use to get different interfaces from the dev server. All these URLs are ephemeral, we do not guarantee that they will be available, or the same at any future point. In order to work with them, we recommend re-requesting the dev server every time you want to use them.

URLDescription
ephemeralUrlThis url displays whatever is on port 3000 of the dev server, or a loading indicator until that shows up
mcpEphemeralUrlThis url is an MCP that lets your AI work with the dev server
codeServerUrlThis url opens a VSCode window in the browser that is inside the dev server, useful for letting you/your users collaborate with the AI.

The File System Interface

The dev server provides a file system interface that lets you read and write files in the dev server.

Writing files

You can write files using the fs. The default encoding is utf-8, but you can specify another one (like base64) if you want to upload something like an image.

await fs.writeFile("src/index.tsx", `console.log("Hello World!");`);
fs.write_file("/test.txt", "Hello, Freestyle!")

Reading files

You can read files using the fs. The default encoding is utf-8, but you can specify another one (like base64) if you want to download something like an image.

const content = await fs.readFile("src/index.tsx");

console.log(content);
content = fs.read_file("src/index.tsx")

print(content)

Listing files

You can list files in a directory using the fs. This is not a recursive listing, it only lists files in the specified directory. If you want to list files recursively, you'll want to use the process interface to run a command like ls -R or find ..

const files = await fs.ls("src");

console.log(files);
files = fs.ls("src")

print(files)

Executing Commands

You can execute any command on the dev server using the process interface.

const { stdout, stderr } = await process.exec("npm run dev");

console.log(stdout);
console.error(stderr);
result = process.exec("npm run dev")

print(result.stdout)
print(result.stderr)

Running background tasks

You can run background tasks using the process.exec, by passing a second argument true to the exec function. This will run the task in the background.

await process.exec("npm run dev", true);
// This will run in the background so you can continue doing other things
process.exec("npm run dev", background=True)
# This will run in the background so you can continue doing other things

Committing and Pushing Changes

You can commit and push changes to the repo using the commitAndPush function. This will commit all changes in the dev server and push them to the repo. The commit will go to the branch that the dev server is currently on, which is usually main.

await commitAndPush("Updated index.tsx");
commit_and_push("Updated index.tsx")

Using in NextJS

When building a web interface for your dev server, we provide a FreestyleDevServer component for NextJS. The component automatically keeps the dev server alive.

To use it, you'll first need to create a server action to handle the request. This action will create a dev server for the repo if one isn't already running or return the status if one is already running.

preview-actions.ts
"use server";

import { freestyle } from "@/lib/freestyle";

export async function requestDevServer({ repoId }: { repoId: string }) {
  const { ephemeralUrl, devCommandRunning, installCommandRunning } =
    await freestyle.requestDevServer({ repoId });

  return { ephemeralUrl, devCommandRunning, installCommandRunning };
}

Then, you can use the FreestyleDevServer component in your NextJS app with the requestDevServer action you just created.

import { FreestyleDevServer } from "freestyle-sandboxes/react/dev-server";
import { requestDevServer } from "./preview-actions";

export function Preview({ repoId }: { repoId: string }) {
  <FreestyleDevServer actions={{ requestDevServer }} repoId={repoId} />;
}

Working in Parallel

You can clone the repo locally and try pushing to it. You should see the dev server update in realtime. Note this will only work if you made the repo public, otherwise, you'll need to create git credentials to access the repo. See the Git Documentation for more information.

git clone https://git.freestyle.sh/<repoId>

For production use in App Builders, we suggest using isomorphic-git to manage git from serverless JavaScript environments.

import git from "isomorphic-git";
import fs from "fs";
import http from "isomorphic-git/http/node";

git.clone({
  fs,
  url: "https://git.freestyle.sh/<repoId>",
  singleBranch: true,
  depth: 1,
  http,
});

Model Context Protocol (MCP)

MCP is a protocol for allowing AI agents to discover and use tools. Dev servers automatically expose a set of tools for interacting with the file system and other core operations such as installing npm modules, running commands, and testing code. You can get the url for this server in the dev server response.

We provide the following tools by default:

  • readFile: Read a file from the dev server
  • writeFile: Write a file to the dev server
  • editFile: Search and replace based file editing
  • ls: List files in a directory
  • exec: Execute a command on the dev server
  • commitAndPush: Commit and push changes to the repo
  • npmInstall: Install an npm module on the dev server
  • npmLint: Lint the code on the dev server

Together, these tools make it easy to get your agents started on development. They do not handle everything, but we recommend the MCP as a good starting point for building your own tools.

On Current Limitations

Dev Servers are primarily made to run JavaScript/typescript Dev Servers. When we start a dev server, we run npm run dev and expect it to start a server on port 3000. If you want to add more on startup, you can change the script in npm run dev to run whatever you want. We automatically keep track of the process and restart it if it crashes.

This approach makes it theoretically work with other languages, but in practice not well. We are actively working on improving this. For the best experience today, a good rule of thumb is, "Would this be a part of my npm run dev workflow locally?" If the answer is yes, then it will work well on a dev server. If not, let us know, we'd like to make it work better.

Freestyle AI

Documentation assistant

Experimental: AI responses may not always be accurate—please verify important details with the official documentation.

How can I help?

Ask me about Freestyle while you browse the docs.