LogoFreestyle

SDK Design Patterns

Learn the consistent patterns used throughout the Freestyle SDK.

The Freestyle SDK follows consistent design patterns to make the API predictable and easy to learn. Once you understand these patterns, you'll know how to use any part of the SDK.

Object-Based Parameters

SDK methods take a single object parameter with named properties:

const { vm } = await freestyle.vms.create({
  workdir: "/app",
  ports: [{ port: 443, targetPort: 3000 }],
  persistence: { type: "ephemeral" },
});

This makes it clear what each parameter does and keeps the API flexible as new options are added.

Destructured Returns

Creation methods return an object with both the helper instance and metadata:

const { vm, vmId, domains } = await freestyle.vms.create();
const { identity, identityId } = await freestyle.identities.create();
const { repo, repoId } = await freestyle.git.repos.create();

The helper instance is always named after the namespace noun (e.g., vm from vms, identity from identities). This gives you both the instance for interacting with the resource and the IDs/metadata you need.

Namespaced Structure

APIs are organized by resource type with consistent operations:

freestyle.vms.create()
freestyle.vms.list()
freestyle.vms.delete({ vmId })

freestyle.git.repos.create()
freestyle.git.repos.list()
freestyle.git.repos.delete({ repoId })

freestyle.identities.create()
freestyle.identities.list()
freestyle.identities.delete({ identityId })

The pattern is freestyle.<resource-plural>.<operation>() where operations include create, list, delete, update, etc.

Delete operations use the namespace

const { repoId } = await freestyle.git.repos.create({ ... });
await freestyle.git.repos.delete({ repoId });

This works whether you created the resource in the current code or are referencing one that exists elsewhere.

Flexible Resource References

Parameters accept multiple formats for the same resource type:

// Using a full URL
const { vm } = await freestyle.vms.create({
  gitRepos: [{
    repo: "https://github.com/owner/repo",
    path: "/app"
  }]
});

// Using a Freestyle repo ID
const { vm } = await freestyle.vms.create({
  gitRepos: [{
    repo: "repo_abc123",
    path: "/app"
  }]
});

The SDK automatically handles different formats, so you can use whatever is most convenient.

Inline Configuration Options

Options are specified inline with string literals:

const { vm } = await freestyle.vms.create({
  persistence: {
    type: "ephemeral",
    deleteEvent: "OnSuspend",
  }
});

const { vm } = await freestyle.vms.create({
  persistence: {
    type: "sticky",
    priority: 5,
  }
});

TypeScript's autocomplete will show you all available options as you type.

Consistent List Operations

All list operations follow the same pattern:

const { vms, nextPageToken } = await freestyle.vms.list({
  pageToken?: string,
  pageSize?: number,
  filter?: { ... }
});

const { repos, nextPageToken } = await freestyle.git.repos.list({
  pageToken?: string,
  pageSize?: number,
  filter?: { ... }
});

Lists return an object with the resource array (matching the namespace name) and an optional nextPageToken for pagination.

Practical Examples

Creating resources with proper destructuring

// VMs
const { vm, vmId, domains } = await freestyle.vms.create({
  ports: [{ port: 443, targetPort: 3000 }],
});

// Git repos  
const { repo, repoId } = await freestyle.git.repos.create({
  url: "https://github.com/company/repo",
});

// Identities with permissions
const { identity, identityId } = await freestyle.identities.create();
await identity.permissions.vms.create({
  vmId: vmId,
});
const { token } = await identity.createToken();

Using helper instances

// VM instance methods
await vm.start();
await vm.suspend();
await vm.exec("npm install");

// Identity instance methods
await identity.permissions.vms.create({ vmId });
const { tokens } = await identity.listTokens();

Familiar APIs use standard conventions

Some helpers like filesystem operations follow established conventions:

// Filesystem uses positional parameters (like Node.js fs)
await vm.fs.writeTextFile("/app/config.json", JSON.stringify(config));
const content = await vm.fs.readTextFile("/app/config.json");

// Simple operations can return values directly
const result = await vm.exec("ls");
const text = await vm.fs.readTextFile("/file.txt");

List and delete patterns

// List all VMs
const { vms } = await freestyle.vms.list();

// List with pagination
const { vms, nextPageToken } = await freestyle.vms.list({
  pageSize: 50,
});

if (nextPageToken) {
  const { vms: moreVms } = await freestyle.vms.list({
    pageToken: nextPageToken,
  });
}

// Delete resources using namespace method
await freestyle.vms.delete({ vmId: vm.vmId });
await freestyle.git.repos.delete({ repoId: repo.repoId });
await freestyle.identities.delete({ identityId: identity.identityId });

Resource references in multiple formats

// Snapshots accept VM ID or snapshot ID
const { vm } = await freestyle.vms.create({
  snapshotId: "snap_abc123",
});

// Git repos accept URL or Freestyle repo ID
const { vm } = await freestyle.vms.create({
  gitRepos: [
    { repo: "https://github.com/owner/repo", path: "/app" },
    { repo: "repo_xyz789", path: "/lib" },
  ],
});

Why These Patterns?

These patterns make the SDK:

  • Predictable - If you know how one API works, you know how they all work
  • Discoverable - TypeScript autocomplete guides you to the right usage
  • Flexible - New features can be added without breaking existing code
  • Type-safe - Catch errors at compile time instead of runtime
  • Readable - Code is self-documenting with named parameters

On this page

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.