Skip to content

Persistent Storage (store) ​

In Carotene, data storage is split into two distinct primitives to eliminate ambiguity: volatile memory (state) and durable disk storage (store).

The store block is your database. Data defined inside a store is guaranteed to survive server restarts, page reloads, and application crashes. By strictly isolating disk I/O from RAM, Carotene ensures that AI-generated code cannot accidentally wipe critical user data or cause massive database bottlenecks by treating a database cluster like a local variable.

Contextual Defaults (The Magic) ​

Carotene's Inference Engine reads where the store is located in your .carrot file and automatically generates the optimal infrastructure for that environment.

You do not write database connection boilerplate. The compiler handles the migrations, the connection pooling, and the ORM schemas automatically.

  • Backend Environment: The compiler defaults to Postgres. It generates your SQL migration files and a strictly typed ORM schema.
  • Frontend Environment (Web): The compiler defaults to IndexedDB, generating an offline-first browser database.
  • Frontend Environment (Mobile): The compiler defaults to SQLite, generating a high-performance local database file on the iOS/Android device.
dart
backend {
  // Generates a default Postgres database + ORM
  store {
    model Post { 
      id: UUID { primary, generated: true }
      title: String
    }
  }
}

Multiple Databases (Named Stores) ​

Enterprise applications rarely rely on a single database paradigm. You might need relational data for billing, but graph data for a recommendation engine.

Carotene handles "Polyglot Persistence" effortlessly. Just like you can name a backend to create a microservice, you can name a store to provision a completely separate database cluster within the same application.

If a store is unnamed, it acts as your primary default. If it is named, it generates isolated infrastructure.

dart
backend {
  
  // 1. Primary Database (Defaults to Postgres)
  store {
    model User { id: UUID, email: String }
  }

  // 2. Secondary Database (Overridden to MongoDB)
  store Analytics {
    config { mongodb: { uri: "env.MONGO_URI" } }
    
    model EventLog { 
      id: UUID { primary, generated: true }
      payload: JSON 
    }
  }
}

The Verbs: Safe CRUD Operations ​

When instructing the AI to interact with a store, you must use Carotene's four explicit database verbs: creates, reads, updates, and deletes.

(Note: The mutates verb is physically banned from being used on a store; it is reserved exclusively for volatile state to prevent accidental database writes).

When using multiple databases, you simply prefix the model with the store's name.

dart
backend {
  function ProcessUserEvent(userId: UUID, eventData: JSON) {
    // Explicitly grants SELECT permissions on the Primary Postgres DB
    reads store.User
    
    // Explicitly grants INSERT permissions on the Secondary MongoDB DB
    creates store.Analytics.EventLog
  }
}

The AI Execution Sandbox ​

This separation of verbs is not just for human readability; it is the absolute foundation of Carotene's Zero-Trust AI generation.

When the Carotene compiler generates the implementation stubs for the AI, it uses Strict Dependency Injection based exactly on your verbs.

If you assign a function the reads store.User verb, the database client injected into the AI's execution sandbox simply does not have write methods compiled into it.

  • AI attempts to write: ctx.db.user.insert(...)
  • Sandbox Result: TypeScript/Compiler Error: Property 'insert' does not exist on type 'ReadOnlyStore<User>'.

The AI is structurally forced to adhere to your data lifecycle rules. It cannot drop a table, overwrite a record, or delete user data if you did not explicitly grant it the updates or deletes verb.

Overriding the Defaults (The Control) ​

As shown in the Analytics example above, you can override Carotene's defaults at any time using a typed config block. Because the config block is strictly typed, the compiler knows exactly what connection parameters to ask for, providing autocomplete and validation right in your blueprint.

The Zero Lock-in Advantage: When you change a config (e.g., swapping Postgres for MySQL), the AI's business logic implementation does not need to change. The Carotene compiler simply swaps out the underlying ORM and infrastructure scaffolding. This allows you to migrate databases with near-zero friction.