Quickstart
This guide covers installation, your first Sprite, and everything you need to build with persistent execution environments.
Install the CLI
Section titled “Install the CLI”Install with our install script (macOS/Linux):
curl -fsSL https://sprites.dev/install.sh | shThis auto-detects your platform, downloads the binary with checksum verification, and installs to ~/.local/bin.
For Windows or manual installation, see CLI Installation or download from GitHub Releases.
Verify installation:
sprite --helpAuthenticate
Section titled “Authenticate”Sprites uses your Fly.io account for authentication:
sprite org authThis opens a browser window to authenticate with Fly.io.
If authentication fails, try running fly auth logout followed by fly auth login first, then retry sprite org auth.
Create Your First Sprite
Section titled “Create Your First Sprite”sprite create my-first-spriteThis creates a new Sprite with default configuration, running and ready to accept commands.
Set it as your active Sprite to avoid adding -s my-first-sprite to every command:
sprite use my-first-spriteRun Commands
Section titled “Run Commands”Execute commands in your Sprite:
# Run a simple commandsprite exec echo "Hello, Sprites!"
# Run multiple commandssprite exec "cd /tmp && ls -la"
# Open an interactive shellsprite consoleExplore the Environment
Section titled “Explore the Environment”Sprites come pre-configured with common development tools:
# Check available runtimessprite exec "node --version && python3 --version && go version"
# Install packagessprite exec "pip install requests"
# Clone a repositorysprite exec "git clone https://github.com/your/repo.git"Persistence in Action
Section titled “Persistence in Action”Your Sprite’s filesystem persists between commands:
# Create a filesprite exec "echo 'Hello' > /home/sprite/greeting.txt"
# Later, it's still theresprite exec "cat /home/sprite/greeting.txt"View Your Sprite’s URL
Section titled “View Your Sprite’s URL”Every Sprite has a unique HTTP URL:
sprite urlManage Sprites
Section titled “Manage Sprites”# List all spritessprite list
# Destroy when donesprite destroy my-first-spriteUsing the SDKs
Section titled “Using the SDKs”Beyond the CLI, you can create and manage Sprites programmatically:
import { SpritesClient } from '@fly/sprites';
const client = new SpritesClient(process.env.SPRITE_TOKEN);
const sprite = await client.createSprite('my-sprite');
// Execute a commandconst result = await sprite.execFile('python', ['-c', "print('hello')"]);console.log(result.stdout);
// Stream output from long-running commandsconst cmd = sprite.spawn('bash', ['-c', 'for i in {1..10}; do date +%T; sleep 0.5; done']);for await (const line of cmd.stdout) { process.stdout.write(line);}
await sprite.delete();package main
import ( "context" "fmt" "io" "os"
sprites "github.com/superfly/sprites-go")
func main() { ctx := context.Background() client := sprites.New(os.Getenv("SPRITE_TOKEN"))
sprite, _ := client.CreateSprite(ctx, "my-sprite", nil) defer client.DeleteSprite(ctx, "my-sprite")
// Execute a command cmd := sprite.Command("python", "-c", "print('hello')") output, _ := cmd.Output() fmt.Println(string(output))
// Stream output from long-running commands cmd = sprite.Command("bash", "-c", "for i in {1..10}; do date +%T; sleep 0.5; done") stdout, _ := cmd.StdoutPipe() cmd.Start() io.Copy(os.Stdout, stdout) cmd.Wait()}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