concile
Get Started

What is concile?

An open-source reactive backend you host yourself.

Concile is an open source, reactive backend that you host yourself. You write your backend as normal TypeScript functions, and Concile automatically keeps every user's screen up to date.

Think of how a Google Doc works. When one person types, everyone else sees the change right away, and nobody has to click a refresh button. Concile gives your entire app that same magic for any kind of data, and you barely have to think about it.

The idea in one minute

You really only write two kinds of functions. A query reads data, and a mutation writes data. Your app subscribes to a query, like "give me all the messages in this chat."

When someone sends a message, they call a mutation. Concile immediately notices that this mutation changed data your query was looking at. It re-runs the query and pushes the new result to everyone watching that chat. You never have to write polling loops, manage WebSockets, or deal with cache invalidation. That is the whole point of the product.

subscribe data changed push update Your app Query (reads data) Mutation (writes data) Database

The developer experience is built entirely around that reactive model, with one defining trait: you run concile yourself, on your own infrastructure, with no managed cloud in the middle.

You write your backend as functions

Your functions live in a concile/ folder:

schema.ts
messages.ts

Here's a query that lists messages and a mutation that adds one:

concile/messages.ts
import { v } from "@concile/values";
import { query, mutation } from "./_generated/server";

// Reads data. Your app subscribes to this and gets live updates.
export const list = query({
  handler: (ctx) => ctx.db.query("messages", "by_creation").collect(),
});

// Writes data. Runs as one transaction.
export const send = mutation({
  args: { author: v.string(), body: v.string() },
  handler: (ctx, args) => ctx.db.insert("messages", args),
});

There are three function types in total:

  • Query reads data. Your app subscribes to queries and they update on their own.
  • Mutation writes data. Each one runs as a single transaction: it all saves, or none of it does.
  • Action is for everything else, like calling another API or sending an email. Actions can't read or write the database directly; they call your queries and mutations to do that.

You'll meet each one properly in Queries, Mutations, and Actions. If you want to know how the live updates actually work, that's How it works.

What comes with it

concile is a full backend, not just a database. Everything here is built and ready to use today:

Auth, notifications, and the rest are components: you turn on only the ones you need, in one config file. See Components.

Run it anywhere

The same app runs, unchanged, in all of these places:

It stores data in SQLite by default, with no setup. When you want a managed database, point it at Postgres with one flag and change nothing else.

How it compares

If you know these tools, here's the short version:

Both give you realtime, but through security rules or a stack of separate services around a database. concile gets its live updates from your own functions, in one process.

For numbers, Performance has measured benchmarks, with the caveats spelled out.

A few honest limits

  • No full-text or vector search yet. It's not built.
  • Functions run in-process, so don't run untrusted code from different tenants on one shared deployment.
  • No built-in HTTPS. Put a proxy like Caddy or nginx in front for that.
  • Multi-node scaling exists but isn't free-forever the way single-node self-hosting is.

Where to go next

On this page