Getting started with Edge Runs
Run code in our lightweight edge environment.
Sign up at admin.freestyle.sh, create an api key, and configure it in your environment.
FREESTYLE_API_KEY=your-api-keynpm i freestyle-sandboxes@betaEdge runs allow you to execute code in a lightweight javascript environment.
Running Code
To create an Edge Run, provide a script exporting the function you want to run.
You'll be returned the result of the function execution along with any logs
generated during the run. The result will be serialized using JSON.stringify,
so make sure your return value is serializable.
import { freestyle } from "freestyle-sandboxes";
const { result, logs } = await freestyle.edge.runs.create<string>({
script: `export default () => {
return "Hello from Edge!";
}`,
config: {
timeout: 3000, // Optional timeout in milliseconds
}
});
console.log(result); // "Hello from Edge!"
console.log(logs); // Logs generated during executionNode Modules
Edge runs have first class support for node modules. You can specify the modules
you want to use in the config.nodeModules field. These modules will be cached
for future runs, making subsequent executions faster.
import { freestyle } from "freestyle-sandboxes";
const { result } = await freestyle.edge.runs.create({
script: `import { z } from 'zod';
export default () => {
const User = z.object({ name: z.string(), email: z.string().email() });
return User.parse({ name: "Alice", email: "alice@example.com" });
}`,
config: {
nodeModules: {
zod: "3.22.4",
},
},
});Peer dependencies are automatically resolved, but you can also specify how they
should be handled using the peerDependencyResolution field.
Env Variables
You can also pass environment variables to your edge runs using the config.env field.
import { freestyle } from "freestyle-sandboxes";
const { result } = await freestyle.edge.runs.create({
script: `export default () => {
return process.env.MY_SECRET;
}`,
config: {
env: {
MY_SECRET: "supersecretvalue",
},
},
});Network Security and proxying
By default, edge runs have complete access to the internet. However, you can
restrict access using the networkPermissions field in the config. Permissions
are matched against domains. If you specify allow rules, only those rules will
be allowed, and all other requests will be blocked. If a request is blocked, the
request will throw an error.
import { freestyle } from "freestyle-sandboxes";
freestyle.edge.runs.create({
script: `export default async () => {
await fetch("https://not-example.com");
return "Hello from Edge!";
}`,
config: {
networkPermissions: [
{
action: "allow",
query: "example.com",
behavior: "exact",
},
]
}
});If you want to deny specific domains while allowing all others, you can use the deny action.
import { freestyle } from "freestyle-sandboxes";
freestyle.edge.runs.create({
script: `export default async () => {
const err = await fetch("https://blocked-domain.com").catch(e => e.message);
return err;
}`,
config: {
networkPermissions: [
{
action: "deny",
query: "blocked-domain.com",
behavior: "exact",
},
]
}
});You can also proxy network requests through your own proxy server using the
proxy field. It's sometimes useful to also include custom headers, which will
be applied to all requests made inside the edge run.
import { freestyle } from "freestyle-sandboxes";
freestyle.edge.runs.create({
script: ``,
config: {
proxy: "http://my-proxy-server.com",
},
headers: {
"Proxy-Authorization": "Basic base64encodedcredentials"
}
});Listing Edge Runs
import { freestyle } from "freestyle-sandboxes";
const { runs } = await freestyle.edge.runs.list({
limit: 10,
});
console.log(runs);[
{
runId: "6cfcae22-f9a0-46d5-89bf-2b55eb1e6c14",
createdAt: "2025-11-07T21:58:48.511978Z",
startedAt?: "2025-11-07T21:58:48.536538Z",
status: "complete"
}
]You can paginate through edge runs using the cursor field.
import { freestyle } from "freestyle-sandboxes";
let hasMore = true;
let nextCursor = undefined;
while (hasMore) {
const { runs, nextCursor: newCursor } = await freestyle.edge.runs.list({
limit: 10,
cursor: nextCursor,
});
console.log(runs);
nextCursor = newCursor;
hasMore = !!nextCursor;
}