What is Adama?
Adama is hard to pin down with a single definition because it smashes together concepts that normally live in completely separate worlds. So instead of one tidy sentence, I'll give you three mental models. Each one captures a different facet of what's going on, and together they paint the full picture.
Mental Model 0: The Sleeping Virtual Machine
Before the other mental models, there's a foundational insight that shapes everything. Think about how your computer can suspend -- power off, even -- then power back on exactly where you were. When it works, it feels like magic.
Adama uses this exact model for backend code:
┌─────────────────────────────────────────────────────────────────┐
│ Document Lifecycle │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ SLEEP │─────>│ WAKE │─────>│ ACTIVE │ │
│ │ (Disk) │ 1 │ (Load) │ 2 │ (Memory)│ │
│ └──────────┘ └──────────┘ └────┬─────┘ │
│ ^ │ │
│ │ v │
│ │ ┌──────────────────────────────┐ │
│ │ │ Process Messages (3.a) │ │
│ │ │ Persist Changes (3.b) │ │
│ │ └──────────────────────────────┘ │
│ │ │ │
│ │ v │
│ │ ┌──────────┐ │
│ └────────────│ SLEEP │ 4 │
│ │ (Idle) │ │
│ └──────────┘ │
└─────────────────────────────────────────────────────────────────┘
- Wake: When the first user connects, the document wakes by loading a snapshot from disk
- Load: The state is restored into memory, ready to execute
- Process: As users interact (3.a), their messages change the document's state. These changes are persisted as differentials (3.b)
- Sleep: When all users disconnect or the system needs to move the document elsewhere, it sleeps - returning to disk
This isn't just an analogy. It's the actual architecture. Each document is a tiny virtual machine that wakes up on demand, processes interactions through messages, persists only what changed (not the entire state), and sleeps when idle.
The transactional boundary in Adama is a single message. One message in, one data differential out. All state changes either commit together or rollback together. You never think about partial failures or inconsistent states -- that's the runtime's problem, not yours.
This model answers the questions that matter: How many documents can a server host? How fast does a document wake from disk? How much does persistence cost? The answers are all "remarkably cheap" because Adama is designed around tiny incremental differentials rather than full-state snapshots.
Mental Model 1: The Reactive Spreadsheet
Think about how Excel works. You type =A1+B1 into cell C1, and something powerful happens: C1 automatically updates whenever A1 or B1 changes. You don't recalculate anything. The spreadsheet tracks dependencies and does the work for you.
Adama brings this same idea to backend programming:
public int x = 3;
public int y = 4;
public formula hypotenuse = Math.sqrt(x * x + y * y);
The formula keyword declares a reactive computation. When x or y changes, hypotenuse automatically recomputes. Connected clients get the new value without you writing a single line of update logic.
Formulas are 100% lazy. They only compute when someone actually needs the value, and the result is cached until the underlying data changes. So you can declare expensive formulas without worrying about wasted cycles.
The beauty of this is that reactivity extends to complex queries across tables:
record Player {
public int id;
public string name;
public int score;
}
table<Player> players;
// Automatically updates as scores change
public formula leader = (iterate players order by score desc limit 1);
public formula total_score = (iterate players).score.sum();
Unlike a spreadsheet's grid of cells, you get the full power of records, tables, and SQL-like queries -- all with automatic reactivity baked in.
Mental Model 2: The Database-Code Fusion
Traditional web architecture looks like this:
Client <--> Web Server <--> Database
Your web server has the business logic. Your database stores the data. Between them lies a constant shuttle of data back and forth -- queries, results, transactions, connection pools, ORM mappings, and all the misery that entails. I have written so many connection pool configs in my life.
Adama collapses this into a single unit:
Client <--> Living Document (Code + Data)
Your code is your document. There's no separate database to connect to because the state lives right alongside the logic that manipulates it:
// This IS the database schema AND the code
record Todo {
public int id;
public string text;
public bool completed;
public principal owner;
}
table<Todo> todos;
message CreateTodo {
string text;
}
channel create(CreateTodo msg) {
todos <- { text: msg.text, completed: false, owner: @who };
}
message ToggleTodo {
int id;
}
channel toggle(ToggleTodo msg) {
if ((iterate todos where id == msg.id)[0] as todo) {
todo.completed = !todo.completed;
}
}
This fusion eliminates entire categories of problems:
- No ORM mismatch - There is no mapping between objects and tables because they are the same thing
- No connection pooling - There is no database connection to manage
- No stale cache - There is no separate cache to invalidate
- Guaranteed consistency - Every message is processed as an atomic transaction
Every change to an Adama document is automatically persisted. You never think about "saving." The document is always durable.
Differentiability: The Secret Sauce
Why are tables the key container in Adama? Because of differentiability.
When you use a traditional database, your updates and deletes are effectively data differentials which the database ingests and proxies to disk via a log structure. Adama applies this same principle to your entire application state -- not just the "database" part.
Every state change is monitored. This monitoring produces differentials -- small descriptions of what changed. These differentials power three systems simultaneously:
- Persistence - Changes are appended to a write-ahead log (via Caravan, Adama's storage engine), then fsynced to disk
- Client sync - Only changes are sent over the network, not full state
- Undo - The inverse differential can be applied to rewind state
public int score = 100;
message Empty {}
channel bump(Empty msg) {
// When this line runs:
score += 10;
}
// Adama emits something like: {"score": 110}
// Not: {"player": "Jeff", "score": 110, "name": "...", ...entire document...}
This is why Adama can keep games running forever at minimal cost -- a six-hour game session might involve thousands of moves, but each move produces only a tiny differential. The economics work out beautifully.
Mental Model 3: The Real-time Webserver
Every Adama document is automatically accessible over the network. When you deploy code, you get:
- WebSocket connections for real-time bidirectional communication
- HTTP endpoints for traditional request/response patterns
- Asset hosting for files attached to documents
record Todo {
public int id;
public string text;
public bool completed;
public principal owner;
}
table<Todo> todos;
// Define what happens when someone connects
@connected {
return true; // Allow the connection
}
// Define what the viewer sees based on who they are
bubble my_todos = iterate todos where owner == @who;
Connected clients receive a personalized JSON view of the document. When the document changes, only the differences are sent -- not the entire state. This delta protocol makes real-time updates absurdly efficient.
// Initial connection might send:
{"my_todos": [{"id": 1, "text": "Buy milk", "completed": false}]}
// After marking as complete, client receives only:
{"my_todos": {"1": {"completed": true}}}
The document is the single source of truth. Clients see a projection of that truth filtered by privacy rules. There's no caching layer to invalidate because there's only one place where truth lives. Simple.
Infrastructure as User-Generated Content
Here's a way to think about what Adama enables that I find genuinely exciting:
Just as web browsers turned UI into user-generated content -- shipping dynamically via URLs instead of executables -- Adama turns backend infrastructure into content.
Consider what the browser did for client-side development. Before the web, shipping UI meant shipping executables. Now, a single HTML/CSS/JavaScript bundle can create any user experience, delivered instantly, updated continuously.
Adama does the same thing for the backend. A single text file -- your Adama specification -- represents:
- The data model
- The business logic
- The privacy rules
- The real-time synchronization
- The state machine transitions
Deploy it, and you have infrastructure. Update the file, and the infrastructure changes. Version control it like any other content.
// This single file IS your backend
// It's infrastructure as content
record GameState {
public int id;
public string status;
}
public int players_online;
table<GameState> games;
@connected {
players_online++;
return true;
}
@disconnected {
players_online--;
}
If the browser is a mutable surface to drive user experiences, then Adama is a mutable backend to connect people. Board game logic, chat systems, real-time collaboration, signaling for WebRTC, marketplaces, lobbies -- all deployable, updatable, version-controllable content.
Who Should Use Adama?
Adama excels when your problem has these characteristics:
Multiple users share state
Games, collaboration tools, chat applications, shared dashboards -- anywhere people need to see each other's actions in real-time.
// A simple shared counter
public int count = 0;
message Increment { }
channel increment(Increment msg) {
count++;
} // All connected clients see the update instantly
Privacy matters
When different users should see different data, Adama's privacy modifiers make this trivial:
record Card {
public int id;
private principal owner;
viewer_is<owner> int value; // Only the owner sees the value
}
State machines drive interaction
Board games, wizards, approval workflows -- any process where "what can happen next" depends on current state:
#waiting_for_players {
// Game logic waits here until enough players join
}
#playing {
// Game is in progress
}
#game_over {
// Final state
}
You want simpler infrastructure
Instead of managing databases, caches, message queues, and web servers separately, Adama gives you one thing to deploy. One. I can't overstate how much sanity this saves.
Use Cases
Adama has been used to build:
- Multiplayer board games - The original motivation for creating the language
- Real-time collaboration tools - Shared editing, presence, cursors
- Chat applications - With built-in history and privacy
- Interactive dashboards - Live data with personalized views
- Workflow coordinators - Multi-step processes with human approval
- Turn-based games - Chess, card games, strategy games
What Adama is NOT
Understanding the limits matters. Maybe more than understanding the strengths.
Not a general-purpose language
Adama is deliberately constrained. You cannot:
- Make arbitrary network calls (only through defined services)
- Access the filesystem
- Spawn threads or processes
- Use arbitrary libraries
These constraints are features, not bugs. They enable the guarantees that make Adama powerful: deterministic execution, automatic persistence, and reliable replay. You give up freedom; you get correctness.
Not for computation-heavy workloads
Adama documents run on a single thread. If you need to crunch millions of records or do heavy computation, that work should happen in external services. Adama is for coordination and state management, not number crunching.
Not a replacement for traditional databases at scale
While an Adama document can hold significant state (up to the Java heap size), it's not designed for "big data." Think of each document as scoped to a single game session, a single chat room, or a single user's data -- not an entire enterprise's dataset. That's a different problem.
Not for simple CRUD applications
If your application is mostly "create, read, update, delete" without complex state transitions or real-time requirements, a traditional database and web framework is probably simpler. Use the right tool for the job; Adama isn't trying to be everything.
Adama imposes a document-per-session model. If you try to build a system where all users share one giant document, you'll hit performance limits. The pattern is many small documents, not one big one. Get this wrong and you'll have a bad time.
The Adama Sweet Spot
Adama shines brightest when:
- State is inherently shared between multiple users
- Updates should be real-time without polling
- Privacy rules are complex and vary per user
- State transitions matter and need to be enforced
- Simplicity is valued over maximum flexibility
If your problem fits this profile, Adama can eliminate enormous amounts of complexity compared to building the same thing with traditional tools. And I say that as someone who spent years building the same thing with traditional tools before giving up and making this.
Now that you have a mental model for what Adama is, learn why it was designed this way in Philosophy.