Skip to content

The Backend ​

In Carotene, the backend block defines your server-side environment. It is the secure boundary where durable data is stored, heavy computation occurs, and external public traffic is routed.

Whether you are building a simple Node.js CRUD API or a high-performance Rust microservice architecture, the backend block provides the exact primitives you need, governed by strict compiler boundaries.

Monoliths vs. Microservices ​

Carotene uses namespace merging to determine your deployment architecture.

  • The Monolith: If you use an unnamed backend block across multiple .carrot files, the compiler merges them all into a single, cohesive server deployment.
  • Microservices: If you name your backends (e.g., backend OrderService), the compiler isolates them. It generates independent deployments, distinct database schemas, and wires up the internal gRPC/HTTP service mesh automatically.
dart
// We can define backends at the top level
backend InventoryService {
  config go { version: "1.21" }
  function DeductStock(id: UUID) { ... }
}

backend OrderService {
  config node { framework: "fastify" }
  
  function PlaceOrder(id: UUID) {
    // Magic Service Mesh: Safely calls across the microservice boundary
    calls InventoryService.DeductStock
  }
}

Data & Memory ​

A backend typically manages both durable data (disk) and volatile session data (RAM). Carotene strictly separates these concepts to prevent data loss and optimize infrastructure generation.

  • store: Represents persistent disk storage. By default, Carotene infers a Postgres database and generates SQL migrations and ORM models.
  • state: Represents high-speed, volatile RAM. By default, Carotene infers a Redis cache, perfect for rate-limiting, session management, or active WebSocket state.
dart
backend {
  store {
    model User { id: UUID, email: String }
  }
  
  state {
    model ActiveSession { userId: UUID, lastPing: DateTime }
  }
}

Execution: Functions vs. Loops ​

Computation in the backend happens in two ways: Event-Driven or Continuous.

1. function (Event-Driven) ​

A function is a discrete block of logic triggered by an event (a frontend request, an internal call, or a webhook). It spins up, executes its permitted side-effects, and returns a value or throws an error.

dart
function ProcessPayment(amount: Float) -> Future<Boolean> {
  requires Customer
  updates store.Order
  throws PaymentDeclinedError
}

2. loop (Continuous) ​

A loop runs continuously at a configured frequency. This is used for background workers, polling queues, or high-tick-rate game servers.

dart
loop MatchmakingWorker {
  // Overrides defaults: Runs every 5 seconds
  config polling { rate: "5s" }
  
  reads state.PlayerQueue
  updates store.Match
}

The Gateway: External vs. Internal Traffic ​

Carotene enforces a strict boundary between your internal network and the public internet.

1. Internal Traffic (The Service Mesh): You do not need to define routes for your own frontends or microservices to talk to each other. When a frontend calls backend.ProcessPayment, Carotene auto-generates the secure internal RPC.

2. External Traffic (The Gateway): If you want to expose your backend to third-party developers, webhooks, or external IoT devices, you must explicitly expose the functions using a gateway block.

dart
backend {
  function StripeWebhook(payload: JSON) { ... }

  // Exposing the webhook to the public internet securely
  gateway {
    // Explicit M2M security (bypasses human JWT auth)
    config api_key { source: "header.Stripe-Signature" }
    
    rest {
      POST "/api/v1/webhooks/stripe" -> StripeWebhook()
    }
  }
}

AI Implementation Boundaries ​

The backend is where business logic is most critical. When the AI agent implements a backend function, the Carotene sandbox wraps the generated code in a strict Dependency Injection container.

If the contract says a function only reads store.User, the database client injected into the AI's runtime environment physically will not contain .insert() or .update() methods. The AI is structurally prevented from dropping tables, bypassing auth middleware, or leaking data.