Working with Sprites
After you’ve made it through the Quickstart, you’ve got a working Sprite and a sense of how to use it. This page covers what comes next: how Sprites behave over time, how to run persistent processes, how networking works, and how to shape the environment to fit your stack. Use it as a reference as you start building more with Sprites.
Lifecycle
Section titled “Lifecycle”Automatic Hibernation
Section titled “Automatic Hibernation”Sprites automatically hibernate when inactive, with no compute charges while idle. When you execute a command or make a request to a Sprite’s URL, it automatically wakes up with all your data intact.
Timeouts
Section titled “Timeouts”Sprites currently hibernate after 30 seconds of inactivity. This timeout is not configurable yet.
Idle Detection
Section titled “Idle Detection”A Sprite is considered active if any of the following are true:
- It has an active command running (via
exec) - Its stdin is being written to
- It has an open TCP connection over its URL
- A detachable session is running
Configuration
Section titled “Configuration”Resource Allocation
Section titled “Resource Allocation”Sprites currently use a fixed resource configuration (8 vCPUs, 8192 MB RAM, 100 GB storage). These values are not configurable yet. (SDK config fields are accepted but ignored by the API.)
Working Directory
Section titled “Working Directory”Set the working directory for command execution:
sprite exec -dir /home/sprite/project npm testconst result = await sprite.exec('npm test', { cwd: '/home/sprite/project',});cmd := sprite.Command("npm", "test")cmd.Dir = "/home/sprite/project"output, err := cmd.Output()Environment Variables
Section titled “Environment Variables”sprite exec -env MY_SECRET=hello bash -c 'echo $MY_SECRET'const result = await sprite.execFile('bash', ['-lc', 'echo $MY_SECRET'], { env: { MY_SECRET: 'hello' },});console.log(result.stdout); // hellocmd := sprite.Command("bash", "-c", "echo $MY_SECRET")cmd.Env = []string{"MY_SECRET=hello"}output, _ := cmd.Output()fmt.Println(string(output)) // helloEnvironment
Section titled “Environment”Pre-installed Tools
Section titled “Pre-installed Tools”The default Sprite environment includes:
- Languages: Node.js, Python, Go, Ruby, Rust, Elixir/Erlang, Java, Bun, Deno
- AI Tools: Claude CLI, Gemini CLI, OpenAI Codex, Cursor
- Utilities: Git, curl, wget, vim, and common development tools
Custom Setup
Section titled “Custom Setup”Run setup commands after creating a Sprite:
const sprite = await client.createSprite('my-sprite');
// Install custom dependenciesawait sprite.exec('pip install pandas numpy matplotlib');await sprite.exec('npm install -g typescript');
// Clone a repositoryawait sprite.exec('git clone https://github.com/your/repo.git /home/sprite/project');sprite, _ := client.CreateSprite(ctx, "my-sprite", nil)
// Install custom dependenciessprite.Command("pip", "install", "pandas", "numpy", "matplotlib").Run()sprite.Command("npm", "install", "-g", "typescript").Run()
// Clone a repositorysprite.Command("git", "clone", "https://github.com/your/repo.git", "/home/sprite/project").Run()Interactive Sessions
Section titled “Interactive Sessions”TTY Mode
Section titled “TTY Mode”For interactive applications, enable TTY mode:
# Open interactive shell (TTY enabled by default)sprite console
# Or with execsprite exec -tty bashconst cmd = sprite.spawn('bash', [], { tty: true, rows: 24, cols: 80,});
// Write to stdincmd.stdin.write('echo hello\n');
// Read from stdoutcmd.stdout.on('data', (data) => { process.stdout.write(data);});
// Resize terminalcmd.resize(30, 100);cmd := sprite.Command("bash")cmd.SetTTY(true)cmd.SetTTYSize(24, 80)
cmd.Stdin = os.Stdincmd.Stdout = os.Stdoutcmd.Stderr = os.Stderr
cmd.Start()
// Resize latercmd.Resize(30, 100)
cmd.Wait()Detachable Sessions
Section titled “Detachable Sessions”Create sessions that persist even after disconnecting:
# Create a detachable sessionsprite exec -detachable "npm run dev"
# List active sessionssprite exec
# Attach to a sessionsprite exec -id <session-id>// Create a detachable sessionconst sessionCmd = sprite.createSession('npm', ['run', 'dev']);let sessionId;
sessionCmd.on('message', (msg) => { if (msg && msg.type === 'session_info') { sessionId = msg.session_id; }});
// ... later, attach to itconst cmd = sprite.attachSession(sessionId);cmd.stdout.pipe(process.stdout);// Create a detachable sessioncmd := sprite.CreateDetachableSession("npm", "run", "dev")cmd.Start()
// List sessions to get the session IDsessions, _ := client.ListSessions(ctx, "my-sprite")sessionID := sessions[0].ID
// ... later, attach to itcmd = sprite.AttachSessionContext(ctx, sessionID)cmd.Stdout = os.Stdoutcmd.Run()Listing Sessions
Section titled “Listing Sessions”sprite execconst sessions = await sprite.listSessions();for (const session of sessions) { console.log(`${session.id}: ${session.command}`);}sessions, _ := client.ListSessions(ctx, "my-sprite")for _, session := range sessions { fmt.Printf("%s: %s\n", session.ID, session.Command)}Managing Sprites
Section titled “Managing Sprites”Referencing by Name
Section titled “Referencing by Name”# Set active sprite for current directorysprite use my-sprite
# Commands now use this spritesprite exec echo "hello"// Get sprite by name (doesn't verify it exists)const sprite = client.sprite('my-sprite');
// Get sprite and verify it existsconst sprite = await client.getSprite('my-sprite');// Get sprite by name (doesn't verify it exists)sprite := client.Sprite("my-sprite")
// Get sprite and verify it existssprite, err := client.GetSprite(ctx, "my-sprite")Listing Sprites
Section titled “Listing Sprites”# List all spritessprite list
# List with prefix filtersprite list --prefix "dev-"// List all spritesconst sprites = await client.listAllSprites();
// List with prefix filterconst devSprites = await client.listAllSprites('dev-');
// Paginated listingconst page = await client.listSprites({ maxResults: 50 });console.log(page.sprites);if (page.hasMore) { const nextPage = await client.listSprites({ continuationToken: page.nextContinuationToken, });}// List all spritessprites, _ := client.ListAllSprites(ctx, "")
// List with prefix filterdevSprites, _ := client.ListAllSprites(ctx, "dev-")
// Paginated listingpage, _ := client.ListSprites(ctx, &sprites.ListOptions{MaxResults: 50})fmt.Println(page.Sprites)if page.HasMore { nextPage, _ := client.ListSprites(ctx, &sprites.ListOptions{ ContinuationToken: page.NextContinuationToken, })}HTTP Access
Section titled “HTTP Access”Every Sprite has a unique URL for HTTP access:
# Get sprite URLsprite url
# Make URL public (no auth required)sprite url update --auth public
# Make URL require sprite auth (default)sprite url update --auth default// Get sprite info including URLconst info = await client.getSprite('my-sprite');console.log(info.url);// Get sprite info including URLinfo, _ := client.GetSprite(ctx, "my-sprite")fmt.Println(info.URL)Updating URL settings is available via the CLI, Go SDK, or REST API (the JS SDK does not expose a helper yet).
Port Forwarding
Section titled “Port Forwarding”Forward local ports to your Sprite:
# Forward local port 3000 to sprite port 3000sprite proxy 3000
# Forward multiple portssprite proxy 3000 8080 5432// Forward single portsession, _ := client.ProxyPort(ctx, "my-sprite", 3000, 3000)defer session.Close()// localhost:3000 now forwards to sprite:3000
// Forward multiple portssessions, _ := client.ProxyPorts(ctx, "my-sprite", []sprites.PortMapping{ {LocalPort: 3000, RemotePort: 3000}, {LocalPort: 8080, RemotePort: 80},})Port Notifications
Section titled “Port Notifications”Get notified when ports open in your Sprite:
const cmd = sprite.spawn('npm', ['run', 'dev']);
cmd.on('message', (msg) => { if (msg.type === 'port_opened') { console.log(`Port ${msg.port} opened on ${msg.address} by PID ${msg.pid}`); // Auto-forward or notify user }});cmd := sprite.Command("npm", "run", "dev")cmd.TextMessageHandler = func(data []byte) { var notification sprites.PortNotificationMessage json.Unmarshal(data, ¬ification)
if notification.Type == "port_opened" { fmt.Printf("Port %d opened on %s by PID %d\n", notification.Port, notification.Address, notification.PID) }}cmd.Run()Checkpoints
Section titled “Checkpoints”Save and restore Sprite state:
# Create a checkpointsprite checkpoint create
# List checkpointssprite checkpoint list
# Restore from checkpointsprite restore <checkpoint-id>See Checkpoints and Restore for more details.
Error Handling
Section titled “Error Handling”import { ExecError } from '@fly/sprites';
try { await sprite.execFile('bash', ['-lc', 'exit 1']);} catch (error) { if (error instanceof ExecError) { console.log('Exit code:', error.exitCode); console.log('Stdout:', error.stdout); console.log('Stderr:', error.stderr); }}cmd := sprite.Command("bash", "-lc", "exit 1")err := cmd.Run()
if err != nil { if exitErr, ok := err.(*sprites.ExitError); ok { fmt.Printf("Exit code: %d\n", exitErr.ExitCode()) }}Cleanup
Section titled “Cleanup”Always clean up Sprites when you’re done:
sprite destroy my-spriteawait sprite.delete();// orawait client.deleteSprite('my-sprite');err := client.DeleteSprite(ctx, "my-sprite")Optional: Mount Sprite Filesystem Locally
Section titled “Optional: Mount Sprite Filesystem Locally”Add this helper function to your .zshrc or .bashrc to mount your Sprite’s home directory locally:
# Add to ~/.zshrcsc() { local sprite_name="${1:-$(sprite use)}" local mount_point="/tmp/sprite-${sprite_name}" mkdir -p "$mount_point" sshfs -o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3 \ "sprite@${sprite_name}.sprites.dev:" "$mount_point" cd "$mount_point"}Then use it with:
sc my-sprite # Mounts and cd's to the sprite's filesystemNext Steps
Section titled “Next Steps”- CLI Reference - Full command documentation
- JavaScript SDK - Complete SDK reference
- Go SDK - Native Go integration
- Lifecycle & Persistence - Deep dive into how Sprites work
- Networking - URLs, ports, and connectivity