Guide

Your first backend

Once your agent is connected, you build by describing what the product does. This walks the loop end to end on a task app: the description, the plan, what the executor writes, what the post-build checks assert, and what happens the first time you ask for something destructive. Every behaviour here is what the platform does today, including where it stops and asks.

Section
Get running
Reading time
6 min
Last updated
August 29, 2026

Write a description that contains decisions

The highest-leverage thing you do in this workflow is decide things in the description. Compare "I need a backend for my task app" with:

A description with decisions in it
A task manager. Users sign up with email.
Users create projects. Each project has many tasks.
A task has a title, a description, a status of
todo / in_progress / done, and a due date.
Users can only see their own projects and tasks.

That names the entities, the relationships, the field types, the permitted status values, and the access rule. You do not need to know that the last line becomes a row-level security policy — but because you wrote it, it becomes one. What you leave out gets a default; what you state gets built as stated.

You can also skip the prose and hand your agent SQL. `apply_migration` takes ordinary PostgreSQL DDL — `CREATE TABLE`, `ALTER TABLE ADD COLUMN` / `RENAME COLUMN` / `ADD CONSTRAINT` / `ALTER COLUMN SET`|`DROP NOT NULL`, `CREATE [UNIQUE] INDEX` — multiple statements, semicolon-separated. Your DDL is applied as written: declared `NOT NULL`, `DEFAULT`, and nullability are honoured exactly.

What actually runs

  1. Input

    Your description, or DDL

    Reaches the platform through `backend_chat` or `apply_migration` over MCP.

  2. Plan

    Intent becomes typed actions

    A planner derives entities, relations, columns and policies, then compiles them into a sequence of governed actions. The model never writes SQL directly into your database — it produces a plan the executor runs.

  3. Apply

    One kernel, all-or-nothing

    Every mutation goes through `executeAction`, whether it came from you, your agent, or an automated repair. Schema-mutating actions — creating a table, adding, dropping or renaming a column, adding a constraint or index, enabling auth, vector search or teams — snapshot the schema before they run, so the change can be rolled back to a saved version. An operation the parser cannot map is refused with the route forward, never silently dropped.

  4. Verify

    The backend is exercised, not assumed

    Checks run against the live runtime over real HTTP and return their evidence with the result.

  5. Output

    A schema, endpoints, auth, and policies

    Tables in your project's own PostgreSQL schema, REST endpoints resolved from the catalog, project-scoped JWT auth, and row-level security enforced in the database.

Three columns are provisioned for you on every table Backenly creates, and their naming is a known wart rather than a rule you can infer: `id` (uuid primary key), `"createdAt"` and `"updatedAt"` (camelCase, timestamptz), and `"deleted_at"` (snake_case, soft delete). Order by `createdAt`, filter soft deletes on `deleted_at`, quote the camelCase identifiers in raw SQL — unquoted they fold to lowercase and will not resolve. Declaring any of the three yourself is skipped and reported. Columns you declare exist exactly as you wrote them.

Read the verification, not the success message

The common failure mode of generated infrastructure is the confident lie: the system reports success and the backend does not work. After a build, Backenly runs checks against the live runtime and returns each one with its evidence, into your agent's reply and into the project's activity journal.

CheckWhat it asserts
CRUD lifecyclecreate → read → update → delete, then a post-delete read returns nothing
Auth flowsignup → token issuance → JWT verification → protected resource access
RLS two-user isolationuser A inserts a row; user B is signed in and sees none of it
Live HTTP endpointssignup → JWT → GET list → POST create, over real HTTP rather than in-process
Trigger / function executiona database event fires and the function's last-run timestamp advances
Webhook HMACan invalid signature is rejected with 401

The isolation check is the one to read on any backend holding private data. It is behavioural: a second user is created and signed in, and the assertion is that they receive zero rows — not that the policy text looks right. A wrong policy does not fail loudly on its own; it quietly shows one user another user's data.

Checks that do not apply are reported as skipped, and a skip is never counted as a pass. If verification cannot run at all, the reply says so rather than implying it passed.

Connect a frontend

What you have now is a standard REST API. The SDK is one install and a factory call:

The per-table surface
import { createClient } from '@backenly/sdk'
const backend = createClient({ projectId, apiKey })

await backend.auth.signUp({ email, password })
await backend.auth.signIn({ email, password })

const open = await backend.tasks.list({
  where: { status: 'todo' },
  orderBy: 'due_date',
  order: 'asc',
  limit: 25,
})

const task = await backend.tasks.create({ title: 'Ship onboarding', status: 'todo' })
await backend.tasks.update(task.id, { status: 'in_progress' })
await backend.tasks.delete(task.id)

const remaining = await backend.tasks.count({ status: 'todo' })

Because access control lives in the database, that `list` call is already scoped to the signed-in user. You never write "filter tasks by current user" logic, which means you cannot forget it on one screen. The full contract — both query grammars, the two authentication headers, and where the SDK is the wrong tool — is in the data API guide.

Changing a schema that has rows in it

Creating tables on an empty project is the easy half. The test is week six, when the change touches live data. Additive changes run without ceremony:

Iterating
Add a comments table. Each task can have many comments.
A comment has a body and belongs to a user.

Destructive ones do not. Ask to drop a table and the operation stops before anything runs. Over MCP it never even reaches a tool — destructive operations are absent from the advertised surface — so it is parked in the Review Queue with an approval id, and the dashboard card names the target, the live row count where it can be read, and whether the data is recoverable. A confirmation replays the exact stored call rather than re-deriving it from your words, and it expires: fifteen minutes for a named confirmation, two minutes for a bare "yes", so a forgotten approval cannot fire the next morning.

Backenly does

  • Plans the change against the live schema and applies it through one governed kernel.
  • Captures a pre-migration snapshot before creating a table.
  • Runs the verification checks and reports each result with its evidence.
  • Refuses to execute a destructive operation without an explicit human confirmation.

You own

  • Read the plan before confirming it — that is the moment to add the field you forgot.
  • Read the isolation check on anything holding private data.
  • Decide whether a destructive change should happen at all.
  • Own your frontend, your product decisions, and your data model's correctness.

Where this is the wrong tool

A described backend fits when your product has a recognisable shape: users, content, relations, permissions, files, scheduled work. It is the wrong tool when the backend is the product — a database engine, a system with microsecond latency budgets, or one whose regulation requires owning every line.

There is also a hard boundary worth knowing early: Backenly exposes no SQL functions, so there is no `rpc()` surface. Custom logic runs as a function attached to an event, a schedule, or an HTTP endpoint instead. If your business logic is hundreds of interlocking rules, you want engineers writing it, with the platform handling the infrastructure underneath them.

In short

Describe the backend with the decisions in it, read the plan, let the governed executor apply it, and judge the result by the verification evidence rather than the success message. Then keep iterating in plain English — additive changes run, destructive ones stop and ask, and every governed change is recorded.

Adarsh Chiriyamkandath Jose

Founder, Backenly · Updated August 29, 2026

Try it on a live project

One free project, no credit card. Connect your agent over MCP and read the verification evidence yourself.

Create a project