Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/superfly/sprites-go/llms.txt

Use this file to discover all available pages before exploring further.

Checkpoints let you freeze the current state of a sprite and restore it at any point. Unlike a full restart, a restore brings the sprite back to exactly the filesystem and process state it was in when the checkpoint was taken — making them useful for reproducible test baselines, safe deployment gates, and reversible experiments.

The Checkpoint struct

Every checkpoint is represented as a Checkpoint value with the following fields:
type Checkpoint struct {
    ID         string    `json:"id"`
    CreateTime time.Time `json:"create_time"`
    History    []string  `json:"history,omitempty"`
    Comment    string    `json:"comment,omitempty"`
    IsAuto     bool      `json:"is_auto,omitempty"`
}
FieldDescription
IDUnique identifier for this checkpoint. Pass it to GetCheckpoint or RestoreCheckpoint.
CreateTimeWhen the checkpoint was taken.
HistoryOrdered list of ancestor checkpoint IDs, oldest first.
CommentOptional human-readable label set at creation time.
IsAutotrue for checkpoints created automatically by the platform.

Creating a checkpoint

1

Get a sprite handle

Obtain a Sprite from your client using the sprite’s name.
client := sprites.New(os.Getenv("SPRITE_TOKEN"))
sprite := client.Sprite("my-sprite")
2

Call CreateCheckpoint or CreateCheckpointWithComment

Both methods return a *CheckpointStream that streams progress messages while the snapshot is being taken.
stream, err := sprite.CreateCheckpoint(ctx)
if err != nil {
    log.Fatal(err)
}
3

Consume the stream

The checkpoint operation streams StreamMessage values until the snapshot is complete. Call ProcessAll to handle every message and automatically close the stream when done.
err = stream.ProcessAll(func(msg *sprites.StreamMessage) error {
    switch msg.Type {
    case "info":
        fmt.Println("info:", msg.Data)
    case "error":
        return fmt.Errorf("checkpoint error: %s", msg.Error)
    }
    return nil
})
if err != nil {
    log.Fatal(err)
}

Streaming messages

Both CheckpointStream and RestoreStream deliver StreamMessage values:
type StreamMessage struct {
    Type  string `json:"type"` // "info", "stdout", "stderr", "error"
    Data  string `json:"data,omitempty"`
    Error string `json:"error,omitempty"`
}
TypeMeaning
"info"Progress update from the platform. Read from Data.
"stdout"Standard output from an internal process. Read from Data.
"stderr"Standard error from an internal process. Read from Data.
"error"A fatal error occurred. Read from Error.

Manual iteration with Next

Use Next when you need to control the loop yourself — for example to stop early:
defer stream.Close()

for {
    msg, err := stream.Next()
    if err == io.EOF {
        break
    }
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("[%s] %s\n", msg.Type, msg.Data)
}
Always close the stream when you are done. ProcessAll calls Close automatically; if you use Next directly, use defer stream.Close().

Listing checkpoints

ListCheckpoints

Returns all manually created checkpoints. Pass an empty string for historyFilter to retrieve all of them, or pass a checkpoint ID to retrieve only that checkpoint’s ancestors.
checkpoints, err := sprite.ListCheckpoints(ctx, "")
if err != nil {
    log.Fatal(err)
}

for _, cp := range checkpoints {
    fmt.Printf("%s  %s  %s\n", cp.ID, cp.CreateTime.Format(time.RFC3339), cp.Comment)
}

ListCheckpointsWithOptions

Use ListCheckpointsWithOptions when you need finer control:
opts := sprites.ListCheckpointsOptions{
    HistoryFilter: "",    // empty = all checkpoints
    IncludeAuto:   true,  // also return auto-created checkpoints
}

checkpoints, err := sprite.ListCheckpointsWithOptions(ctx, opts)
if err != nil {
    log.Fatal(err)
}
IncludeAuto: true includes checkpoints where IsAuto == true. These are created by the platform during certain operations and are hidden by default.

Getting a specific checkpoint

Retrieve a single checkpoint by its ID to inspect its metadata before deciding whether to restore it:
checkpoint, err := sprite.GetCheckpoint(ctx, "cp_abc123")
if err != nil {
    log.Fatal(err)
}

fmt.Printf("ID:      %s\n", checkpoint.ID)
fmt.Printf("Created: %s\n", checkpoint.CreateTime.Format(time.RFC3339))
fmt.Printf("Comment: %s\n", checkpoint.Comment)
fmt.Printf("IsAuto:  %v\n", checkpoint.IsAuto)

Restoring a checkpoint

RestoreCheckpoint rolls the sprite back to the state captured in the given checkpoint. It returns a *RestoreStream with the same interface as CheckpointStream.
stream, err := sprite.RestoreCheckpoint(ctx, "cp_abc123")
if err != nil {
    log.Fatal(err)
}

err = stream.ProcessAll(func(msg *sprites.StreamMessage) error {
    if msg.Type == "error" {
        return fmt.Errorf("restore failed: %s", msg.Error)
    }
    fmt.Println(msg.Data)
    return nil
})
if err != nil {
    log.Fatal(err)
}

Complete workflow example

The following example creates a checkpoint, lists it to confirm it exists, then restores it:
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "time"

    sprites "github.com/superfly/sprites-go"
)

func main() {
    ctx := context.Background()
    client := sprites.New(os.Getenv("SPRITE_TOKEN"))
    sprite := client.Sprite(os.Getenv("SPRITE_NAME"))

    // 1. Create a checkpoint with a label.
    stream, err := sprite.CreateCheckpointWithComment(ctx, "pre-migration")
    if err != nil {
        log.Fatal(err)
    }
    err = stream.ProcessAll(func(msg *sprites.StreamMessage) error {
        fmt.Println("[create]", msg.Type, msg.Data)
        return nil
    })
    if err != nil {
        log.Fatal(err)
    }

    // 2. List checkpoints and find the one we just created.
    checkpoints, err := sprite.ListCheckpoints(ctx, "")
    if err != nil {
        log.Fatal(err)
    }

    var targetID string
    for _, cp := range checkpoints {
        if cp.Comment == "pre-migration" {
            targetID = cp.ID
            fmt.Printf("Found checkpoint %s created at %s\n",
                cp.ID, cp.CreateTime.Format(time.RFC3339))
        }
    }
    if targetID == "" {
        log.Fatal("checkpoint not found")
    }

    // 3. Restore the sprite to that checkpoint.
    restoreStream, err := sprite.RestoreCheckpoint(ctx, targetID)
    if err != nil {
        log.Fatal(err)
    }
    err = restoreStream.ProcessAll(func(msg *sprites.StreamMessage) error {
        fmt.Println("[restore]", msg.Type, msg.Data)
        return nil
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("Restore complete.")
}

Using the client directly

All methods are also available on *Client if you prefer to pass the sprite name explicitly:
// Client-level equivalents
stream, err := client.CreateCheckpoint(ctx, "my-sprite")
stream, err := client.CreateCheckpointWithComment(ctx, "my-sprite", "label")
checkpoints, err := client.ListCheckpoints(ctx, "my-sprite", "")
checkpoints, err := client.ListCheckpointsWithOptions(ctx, "my-sprite", opts)
checkpoint, err := client.GetCheckpoint(ctx, "my-sprite", checkpointID)
stream, err := client.RestoreCheckpoint(ctx, "my-sprite", checkpointID)
Use the Sprite-level methods (sprite.CreateCheckpoint, etc.) in most code — they are shorter and keep the sprite name in one place. Prefer Client-level methods when you are writing utilities that operate across multiple sprites.

Build docs developers (and LLMs) love