Both are open source backend platforms with auth, a database, storage and functions, available as a managed cloud or self-hosted. They differ most in the database model and how much SQL you write.
Appwrite and Supabase are open source backend platforms that are often compared with Firebase, and both offer auth, a database, file storage, realtime updates and serverless functions, as a managed cloud or self-hosted with Docker. They differ in what sits at the center: Supabase is built around Postgres and SQL, while Appwrite exposes its database through an API with typed tables and row permissions.
This comparison covers the database, access control, functions, hosting and licensing, and where a code-first backend in your own cloud fits instead.
Each option is covered below, starting with Encore.
Encore is infrastructure from code for TypeScript and Go, with a platform that provisions and deploys into your own AWS or GCP account. Instead of a hosted backend with fixed building blocks, you write services with typed endpoints and declare the databases, Pub/Sub topics, cron jobs and buckets they use, and Encore provisions them on AWS or GCP.

Access rules that Appwrite expresses as row permissions and Supabase as RLS policies become ordinary code, with the auth handler supplying the user:
// notes/notes.ts
import { api } from "encore.dev/api";
import { SQLDatabase } from "encore.dev/storage/sqldb";
import { getAuthData } from "~encore/auth";
const db = new SQLDatabase("notes", { migrations: "./migrations" });
interface Note {
id: number;
body: string;
}
// auth: true runs the app's auth handler first; the owner check lives in the query.
export const create = api(
{ expose: true, auth: true, method: "POST", path: "/notes" },
async (req: { body: string }): Promise<Note> => {
const { userID } = getAuthData()!;
const row = await db.queryRow<Note>`
INSERT INTO notes (owner_id, body) VALUES (${userID}, ${req.body})
RETURNING id, body`;
return row!;
},
);
export const mine = api(
{ expose: true, auth: true, method: "GET", path: "/notes" },
async (): Promise<{ notes: Note[] }> => {
const { userID } = getAuthData()!;
const notes: Note[] = [];
for await (const row of db.query<Note>`
SELECT id, body FROM notes WHERE owner_id = ${userID} ORDER BY id`) {
notes.push(row);
}
return { notes };
},
);
The migration in notes/migrations creates the notes table the queries use:
-- notes/migrations/1_create_notes.up.sql
CREATE TABLE notes (
id BIGSERIAL PRIMARY KEY,
owner_id TEXT NOT NULL,
body TEXT NOT NULL
);
Run in your terminal to get started locally.
encore run starts Postgres locally, and requests without valid credentials are rejected before the handler runs. The auth handler can verify tokens from an existing provider, and Encore has an integration guide for Better Auth if you want auth inside the app. A frontend calls the backend through a typed client from encore gen client.
Rules written as code are also easier for AI coding agents to follow and test than policies stored in a dashboard, since an agent can read the owner check in the query and run it against local Postgres.
Best fit: teams that want backend logic and data in their own AWS or GCP account rather than on a hosted backend platform.
Appwrite bundles auth, TablesDB, storage, functions, messaging, realtime and Sites for frontend hosting behind one API and SDKs for web, mobile and server. TablesDB organizes data into databases, tables with typed columns and rows, with relationships, transactions, permissions at table and row level, and generated types.
You do not write SQL against Appwrite, which keeps the client code simple but limits analytical queries and Postgres extensions. Functions run in many runtimes, including Node.js, Python, Dart and Go.
Best fit: mobile and web teams that want an API-first backend with permissions configured per table and row.
Supabase gives every project a full Postgres database with direct connections, extensions like pgvector, and auto-generated REST and GraphQL APIs. Access control is enforced in the database through row-level security policies, so a client can query tables directly while Postgres decides which rows it sees.
Server logic runs in Edge Functions, written in TypeScript on the Deno runtime. RLS policies live in SQL migrations or the dashboard, and Supabase's own docs warn that a table in an exposed schema without RLS is readable and writable by any role with a grant on it.
Best fit: teams that want Postgres and SQL as the foundation, with auth and storage alongside.
Both projects publish Docker-based self-hosting guides, and both are open source, with Appwrite under BSD-3-Clause and Supabase under Apache 2.0. Self-hosting either one means running several containers and handling upgrades and backups yourself.
Choose Supabase when you want Postgres and SQL with access rules in the database. Choose Appwrite when you prefer an API-first backend with row permissions and functions in many languages. Choose Encore when the backend should be your own services and data in your own AWS or GCP account.
Supabase suits teams that want Postgres and SQL, with row-level security, extensions and direct database connections. Appwrite suits teams that prefer an API-first database with table and row permissions, functions in many runtimes and built-in site hosting, working through SDK calls instead of SQL.
Both publish Docker-based self-hosting guides, Appwrite is licensed BSD-3-Clause and Supabase Apache 2.0, and self-hosting means running and upgrading every component yourself.
Appwrite does not expose a Postgres database to your app: data is organized into databases, tables, columns and rows through the TablesDB API and SDKs, with Appwrite's query operators instead of SQL.
With Encore, define an auth handler, mark endpoints with auth: true, and read the user with getAuthData() inside the handler. Filter queries by that user ID, for example WHERE owner_id = ${userID} in a db.query tagged template.
Deploy to your cloud on AWS and Google Cloud
without managing infrastructure
Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.