mech.app
Dev Tools

Twenty CRM's Agent-First Schema: How TypeScript Object Definitions Replace Traditional Database Migrations

Twenty's code-first schema pattern lets agents introspect structure in-process, version data models in Git, and evolve fields without migration scripts.

Source: GitHub
Twenty CRM's Agent-First Schema: How TypeScript Object Definitions Replace Traditional Database Migrations

Twenty CRM positions itself as “the CRM you build, ship, and version like the rest of your stack.” The key technical claim is that schema lives in TypeScript files instead of migration scripts. For agent builders, this pattern solves a specific problem: how do you let an AI add fields, objects, or views to a data model without running database migrations or restarting services?

Traditional ORMs (Prisma, TypeORM, Django) require you to write a migration, apply it to the database, then regenerate TypeScript types. Twenty inverts this: you define objects and fields in code, and the system handles database synchronization. Agents can introspect the schema by reading TypeScript definitions directly, no database round-trip required.

How Twenty Defines Schema in Code

Twenty’s CLI scaffolds apps with a code-first schema pattern. The repository documentation shows you define objects and fields using TypeScript constructs. Based on the Twenty pattern, a typical object definition looks like this:

const Lead = defineObject({
  name: 'Lead',
  fields: {
    email: { type: FieldType.EMAIL, required: true },
    company: { type: FieldType.TEXT },
    lastContacted: { type: FieldType.DATE_TIME },
    score: { type: FieldType.NUMBER }
  }
});

This declaration becomes the source of truth. The object definition includes field types, validation rules, and relationships. When you deploy, Twenty reads these definitions and reconciles the database schema to match.

The pattern differs from traditional ORMs in one key way: schema changes are code changes. You commit them, review them in pull requests, and deploy them with the rest of your application. No separate migration files, no db:migrate step.

Agent Tool Discovery Without Database Queries

When an agent needs to know what fields exist on a Lead object, it can:

  • Read the TypeScript definition directly (if the agent has filesystem access).
  • Call a metadata endpoint that returns the parsed object graph.
  • Use GraphQL introspection to query available fields and types.

All three paths avoid a database query. The schema is already in memory because it was loaded at application startup. This reduces latency for tool discovery and makes it feasible to expose schema introspection as a tool in the agent’s function-calling loop.

Example agent tool signature:

{
  "name": "get_object_schema",
  "description": "Returns all fields and types for a CRM object",
  "parameters": {
    "type": "object",
    "properties": {
      "objectName": {
        "type": "string",
        "enum": ["Lead", "Contact", "Deal"]
      }
    }
  }
}

The agent can call this tool, get back a JSON schema, then construct a valid mutation or query without hardcoding field names.

Common Trade-Offs in Schema Management

Twenty’s code-first approach reflects a broader architectural choice in schema management. Understanding these trade-offs helps teams evaluate whether this pattern fits their agent infrastructure needs:

AspectCode-First PatternMigration-First Pattern
Schema source of truthTypeScript files in version controlMigration scripts + database state
Agent introspectionParse TS or call metadata APIQuery database or regenerate types
RollbackGit revert + redeployRun down migration (risky)
Multi-tenantSame code, different DB state per tenantMigrations run per tenant DB
Schema drift detectionRuntime reconciliation on startupManual diff or CI checks
Type safetySchema and types defined togetherAfter migration + codegen

The code-first approach trades database-level schema versioning for application-level versioning. You lose the ability to inspect migration history in the database itself, but you gain the ability to treat schema like any other code artifact. For agent systems that need to discover and adapt to schema changes programmatically, having schema definitions in TypeScript makes introspection faster and more reliable.

Deployment Shape and Reconciliation Risks

When you deploy a new version of a Twenty app, the application must reconcile the declared schema (in TypeScript) with the actual database state. This creates a tight coupling between application deployment and database schema changes. If you deploy to multiple instances (blue-green, canary), each instance will attempt reconciliation. You need to ensure:

  • Idempotent DDL: The reconciliation engine must detect when a change has already been applied.
  • Lock coordination: Multiple instances should not run conflicting schema changes simultaneously.
  • Backward compatibility: Old code must tolerate new schema (extra columns, new indexes) during rolling deploys.

Twenty’s reconciliation approach compares the desired schema from code against the actual database schema at startup. The system skips changes that are already applied by inspecting current table structures and column definitions. Lock coordination relies on database-level DDL locks, which can cause deployment timeouts if schema changes are slow or if multiple instances attempt reconciliation simultaneously.

Operational Patterns for Production Deployments

Teams deploying Twenty in production need to consider how schema reconciliation behaves across different deployment topologies. While Twenty’s documentation does not specify multi-tenant support, the code-first pattern creates specific operational constraints worth understanding.

If you run schema reconciliation across multiple database instances, you need a migration orchestrator that tracks which instances have been reconciled and handles failures gracefully. If one database’s reconciliation fails, do you block the entire deployment or skip that instance and alert?

A safer pattern is to version schema changes and apply them incrementally:

  1. Deploy code with the new schema definition but mark it as “pending.”
  2. Run a background job that reconciles each database.
  3. Mark the schema as “active” once all databases are reconciled.

This decouples deployment from schema application and gives you a rollback window. For agent systems that need to query schema state, this means you may need to track which schema version is active per database instance.

When to Use Code-First Schema

Code-first schema works well when:

  • Schema changes are frequent: You are building a custom CRM or internal tool where business logic evolves weekly.
  • Agents need introspection: Your AI agents need to discover available fields and construct queries dynamically.
  • Team is TypeScript-native: You already use TypeScript across your stack and prefer type-safe schema definitions.
  • Single-tenant or few instances: You are not managing hundreds of separate databases.

Avoid it when:

  • Schema is stable: If your data model changes once a quarter, migrations are simpler.
  • Large team: Coordinating schema changes in code becomes a merge conflict nightmare.
  • Strict audit requirements: Some industries require database-level migration history.
  • Complex multi-tenancy: Managing schema reconciliation across thousands of databases is operationally risky.

Technical Verdict

Twenty’s code-first schema pattern reduces friction for agent-heavy systems where schema introspection needs to be fast and schema evolution needs to be versioned like application code. The ability to define objects and fields in TypeScript makes it straightforward for agents to discover available tools without querying the database.

The trade-off is operational complexity during deployment. Schema reconciliation must be idempotent, fast, and observable. If you are building a custom CRM or internal tool with frequent schema changes and a small team, this pattern reduces friction. If you are managing a multi-tenant SaaS with strict uptime requirements, traditional migrations give you more control over when and how schema changes are applied.

Use it when you want schema to live in Git and agents to introspect structure in-process. Avoid it when you need database-level migration history or are managing complex deployment topologies with hundreds of database instances.

Tags

agentic-ai schema-as-code dev-tools

Primary Source

GitHub