> ## Documentation Index
> Fetch the complete documentation index at: https://docs.buntime.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Persistence

> How data persists across executions and session states

## Overview

Persistence in buntime.sh means files, data, and state survive across multiple code executions within a session. Understanding how persistence works is crucial for building reliable applications and multi-step workflows.

## What Persists

### ✅ Files in /workspace

All files created in the `/workspace` directory persist:

```typescript theme={null}
// First execution
await client.execute({
  sessionId: session.id,
  code: `
    await Bun.write('data.json', JSON.stringify({ count: 0 }));
    console.log('File created');
  `
});

// Second execution - file still exists
await client.execute({
  sessionId: session.id,
  code: `
    const data = await Bun.file('data.json').json();
    data.count++;
    await Bun.write('data.json', JSON.stringify(data));
    console.log('Count:', data.count); // 1
  `
});
```

### ✅ Installed Packages

Packages installed via `bun add` or auto-installed on import persist:

```typescript theme={null}
// First execution
await client.execute({
  sessionId: session.id,
  command: 'bun add lodash'
});

// Second execution - lodash is available
await client.execute({
  sessionId: session.id,
  code: `
    import _ from 'lodash';
    console.log(_.uniq([1, 2, 2, 3])); // [1, 2, 3]
  `
});
```

### ✅ Database Files

SQLite and other file-based databases persist:

```typescript theme={null}
// First execution
await client.execute({
  sessionId: session.id,
  code: `
    import { Database } from "bun:sqlite";
    const db = new Database("mydb.sqlite");
    db.run("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)");
    db.run("INSERT INTO users (name) VALUES ('Alice')");
    db.close();
  `
});

// Second execution - database still exists
await client.execute({
  sessionId: session.id,
  code: `
    import { Database } from "bun:sqlite";
    const db = new Database("mydb.sqlite");
    const user = db.query("SELECT * FROM users").get();
    console.log(user); // { id: 1, name: 'Alice' }
  `
});
```

### ✅ Background Processes (While Active)

Processes started in previous executions keep running:

```typescript theme={null}
// First execution - start server
await client.execute({
  sessionId: session.id,
  code: `
    Bun.serve({
      port: 8080,
      fetch() {
        return new Response('Hello!');
      }
    });
    console.log('Server started');
  `
});

// Server keeps running in background
// Can be accessed at https://{sessionId}.buntime.sh
```

## What Doesn't Persist

### ❌ In-Memory Variables

Variables only exist during a single execution:

```typescript theme={null}
// First execution
await client.execute({
  sessionId: session.id,
  code: `let myVar = 'hello';`
});

// Second execution - myVar doesn't exist
await client.execute({
  sessionId: session.id,
  code: `console.log(myVar);` // ReferenceError: myVar is not defined
});
```

**Workaround**: Write to files:

```typescript theme={null}
// First execution
await client.execute({
  sessionId: session.id,
  code: `await Bun.write('state.json', JSON.stringify({ myVar: 'hello' }));`
});

// Second execution
await client.execute({
  sessionId: session.id,
  code: `
    const state = await Bun.file('state.json').json();
    console.log(state.myVar); // 'hello'
  `
});
```

### ❌ Files Outside /workspace

Files created outside `/workspace` may not persist:

```typescript theme={null}
// ❌ Don't do this
await client.execute({
  sessionId: session.id,
  code: `await Bun.write('/tmp/data.txt', 'hello');`
});
```

**Always use /workspace**:

```typescript theme={null}
// ✅ Do this
await client.execute({
  sessionId: session.id,
  code: `await Bun.write('/workspace/data.txt', 'hello');`
  // or simply: await Bun.write('data.txt', 'hello');
});
```

### ❌ Environment Variables

Environment variables don't persist between executions:

```typescript theme={null}
// First execution
await client.execute({
  sessionId: session.id,
  code: `process.env.MY_VAR = 'test';`
});

// Second execution - MY_VAR doesn't exist
await client.execute({
  sessionId: session.id,
  code: `console.log(process.env.MY_VAR);` // undefined
});
```

**Workaround**: Pass env vars in each request or write to a file.

### ❌ Processes After Deep Sleep

Processes are terminated after 30 minutes of inactivity:

```typescript theme={null}
// Start a process
await client.execute({
  sessionId: session.id,
  code: `
    Bun.serve({ port: 8080, fetch: () => new Response('OK') });
  `
});

// After 30 minutes of no requests:
// - Session enters deep sleep
// - Server process is terminated
// - Files are saved to R2 storage

// On next request:
// - Session wakes up
// - Files are restored
// - Server process is NOT running
```

## Persistence Across Session States

### Active State

Everything persists in memory:

* Files immediately accessible
* Processes running
* No I/O delays
* Full speed

### Idle State (5 min)

Container sleeps but everything remains:

* Files still in memory
* Processes suspended
* Wake time: instant
* State preserved

### Deep Sleep (30 min)

Filesystem saved to storage:

* Files saved to R2
* Processes terminated
* Wake time: \~3 seconds
* File state preserved

### After Wake

Files restored but processes restarted:

* All files restored from R2
* Need to restart servers
* Database files intact
* Package installations preserved

## Storage Limits

Each session has disk space limits:

| Plan       | Disk Space |
| ---------- | ---------- |
| Free       | 1 GB       |
| Paid       | 5 GB       |
| Enterprise | Custom     |

Monitor disk usage:

```typescript theme={null}
await client.execute({
  sessionId: session.id,
  code: `
    import { spawnSync } from 'bun';
    const result = spawnSync(['du', '-sh', '/workspace']);
    console.log(result.stdout.toString());
  `
});
```

## Database Persistence Patterns

### SQLite

Best for structured data:

```typescript theme={null}
await client.execute({
  sessionId: session.id,
  code: `
    import { Database } from "bun:sqlite";
    const db = new Database("app.db");
    
    db.run(\`
      CREATE TABLE IF NOT EXISTS todos (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        title TEXT,
        completed INTEGER DEFAULT 0
      )
    \`);
    
    db.run("INSERT INTO todos (title) VALUES (?)", "Buy milk");
    console.log("Todo saved");
  `
});
```

### JSON Files

Best for simple state:

```typescript theme={null}
await client.execute({
  sessionId: session.id,
  code: `
    const state = {
      counter: 0,
      lastRun: new Date().toISOString(),
      items: []
    };
    
    await Bun.write('state.json', JSON.stringify(state, null, 2));
  `
});
```

### Redis (In-Memory)

Best for caching and temporary data:

```typescript theme={null}
await client.execute({
  sessionId: session.id,
  code: `
    // Note: Redis data is in-memory and lost on deep sleep
    // Only use for temporary caching
    import { createClient } from 'redis';
    const redis = createClient();
    await redis.connect();
    await redis.set('key', 'value');
  `
});
```

## File Organization Best Practices

### Organize by Purpose

```
/workspace/
  ├── data/              # Application data
  │   ├── cache/
  │   └── uploads/
  ├── src/               # Source code
  │   ├── utils.ts
  │   └── main.ts
  ├── db/                # Databases
  │   └── app.db
  └── config/            # Configuration
      └── settings.json
```

### Use Subdirectories

```typescript theme={null}
await client.execute({
  sessionId: session.id,
  code: `
    import { mkdirSync } from 'fs';
    
    // Create directory structure
    mkdirSync('data/uploads', { recursive: true });
    mkdirSync('src', { recursive: true });
    mkdirSync('db', { recursive: true });
    
    console.log('Directories created');
  `
});
```

## State Management Patterns

### Counter Example

```typescript theme={null}
// Initialize
await client.execute({
  sessionId: session.id,
  code: `
    const counter = { count: 0 };
    await Bun.write('counter.json', JSON.stringify(counter));
  `
});

// Increment
await client.execute({
  sessionId: session.id,
  code: `
    const counter = await Bun.file('counter.json').json();
    counter.count++;
    await Bun.write('counter.json', JSON.stringify(counter));
    console.log('Count:', counter.count);
  `
});
```

### Session Store Example

```typescript theme={null}
await client.execute({
  sessionId: session.id,
  code: `
    class SessionStore {
      constructor(filename = 'session.json') {
        this.filename = filename;
      }
      
      async get(key) {
        try {
          const data = await Bun.file(this.filename).json();
          return data[key];
        } catch {
          return null;
        }
      }
      
      async set(key, value) {
        let data = {};
        try {
          data = await Bun.file(this.filename).json();
        } catch {}
        data[key] = value;
        await Bun.write(this.filename, JSON.stringify(data));
      }
      
      async delete(key) {
        try {
          const data = await Bun.file(this.filename).json();
          delete data[key];
          await Bun.write(this.filename, JSON.stringify(data));
        } catch {}
      }
    }
    
    const store = new SessionStore();
    await store.set('user', { name: 'Alice', age: 30 });
    console.log('Saved');
  `
});
```

## Backup and Recovery

### Manual Backup

Download files before session expires:

```typescript theme={null}
// Read all files
const files = await client.files.list({ sessionId: session.id });

for (const file of files) {
  const content = await client.files.read({
    sessionId: session.id,
    path: file.path
  });
  
  // Save locally
  await Bun.write(`backup/${file.path}`, content);
}
```

### Automatic Snapshots

buntime.sh automatically snapshots your workspace:

* On idle (5 min): In-memory snapshot
* On deep sleep (30 min): R2 snapshot
* On wake: Restore from snapshot

## Common Patterns

<AccordionGroup>
  <Accordion icon="database" title="Persistent Database">
    Always use file-based databases in `/workspace`:

    ```typescript theme={null}
    import { Database } from "bun:sqlite";
    const db = new Database("/workspace/data.db");
    ```
  </Accordion>

  <Accordion icon="upload" title="File Uploads">
    Save uploaded files to disk:

    ```typescript theme={null}
    const file = await req.formData().get('file');
    await Bun.write(\`uploads/\${file.name}\`, file);
    ```
  </Accordion>

  <Accordion icon="cache" title="Caching">
    Use JSON files for simple caches:

    ```typescript theme={null}
    const cache = await Bun.file('cache.json').json().catch(() => ({}));
    cache[key] = value;
    await Bun.write('cache.json', JSON.stringify(cache));
    ```
  </Accordion>

  <Accordion icon="clock" title="Timestamps">
    Track when data was last modified:

    ```typescript theme={null}
    const data = {
      content: 'hello',
      updatedAt: new Date().toISOString()
    };
    await Bun.write('data.json', JSON.stringify(data));
    ```
  </Accordion>
</AccordionGroup>

## Best Practices

<CardGroup cols={2}>
  <Card title="Use /workspace" icon="folder">
    Always write to /workspace to ensure persistence
  </Card>

  <Card title="Close connections" icon="plug">
    Close database connections when done to free resources
  </Card>

  <Card title="Handle missing files" icon="file-circle-question">
    Use try-catch when reading files that might not exist
  </Card>

  <Card title="Clean up" icon="broom">
    Delete temporary files to stay within disk limits
  </Card>
</CardGroup>

## Related Resources

<CardGroup cols={2}>
  <Card title="Sessions" icon="server" href="/concepts/sessions">
    Understanding session lifecycle
  </Card>

  <Card title="Resource Limits" icon="gauge" href="/concepts/resource-limits">
    Disk space and memory limits
  </Card>

  <Card title="Files API" icon="file" href="/api-reference/files/write">
    Managing files via API
  </Card>

  <Card title="Databases Guide" icon="database" href="/guides/databases">
    Working with databases
  </Card>
</CardGroup>
