appwrite-backend

Appwrite BaaS patterns and best practices. Covers TablesDB, Auth, Storage, Functions, Messaging, and Realtime in Dart, Python, and TypeScript. Use when building with Appwrite SDK, Appwrite database, auth, storage, functions, or backend-as-a-service with Appwrite.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "appwrite-backend" with this command: npx skills add sgaabdu4/appwrite-backend/sgaabdu4-appwrite-backend-appwrite-backend

Appwrite Development

Critical Rules

  1. Use TablesDB API — Collections API deprecated in 1.8.0
  2. Use ID.unique() for all IDs — Row IDs (rowId:) and entity IDs in columns. Custom generators with names or timestamps overflow column limits and leak data. Generates ~20-char hex strings client-side.
  3. Use Query.select() — Relationships return IDs only without it
  4. Use cursor pagination — Offset degrades on large tables
  5. Use Operator for counters — Avoids race conditions
  6. Create indexes — Queries without indexes scan entire tables
  7. Init outside handler — SDK/connections persist between warm invocations
  8. Group functions by domain — One per domain, not per operation
  9. Event triggers over polling — One trigger replaces thousands of requests
  10. Use explicit string typesstring deprecated; use varchar or text/mediumtext/longtext
  11. Use appwrite generate — Type-safe SDK from your schema
  12. Use Channel helpers — Type-safe realtime subscriptions, not raw strings
  13. Use Realtime queries — Server-side event filtering, not client-side

Terminology (1.8.0+)

OldNew
CollectionsTables
DocumentsRows
AttributesColumns
DatabasesTablesDB

Setup

import 'package:dart_appwrite/dart_appwrite.dart';

final client = Client()
    .setEndpoint('https://cloud.appwrite.io/v1')
    .setProject('<PROJECT_ID>')
    .setKey('<API_KEY>');

final tablesDB = TablesDB(client);
from appwrite.client import Client
from appwrite.services.tables_db import TablesDB
client = Client()
client.set_endpoint('https://cloud.appwrite.io/v1')
client.set_project('<PROJECT_ID>')
client.set_key('<API_KEY>')
tables_db = TablesDB(client)
import { Client, TablesDB } from 'node-appwrite';
const client = new Client()
    .setEndpoint('https://cloud.appwrite.io/v1')
    .setProject('<PROJECT_ID>')
    .setKey('<API_KEY>');
const tablesDB = new TablesDB(client);

TablesDB CRUD

// Create
await tablesDB.createRow(databaseId: 'db', tableId: 'users', rowId: ID.unique(),
    data: {'name': 'Alice'});

// Read
final rows = await tablesDB.listRows(databaseId: 'db', tableId: 'users',
    queries: [Query.equal('status', 'active'), Query.select(['name', 'email'])]);

// Update
await tablesDB.updateRow(databaseId: 'db', tableId: 'users', rowId: 'user_123',
    data: {'status': 'inactive'});

// Upsert
await tablesDB.upsertRow(databaseId: 'db', tableId: 'settings', rowId: 'prefs',
    data: {'theme': 'dark'});

// Delete
await tablesDB.deleteRow(databaseId: 'db', tableId: 'users', rowId: 'user_123');

Bulk: See bulk-operations.md | Chunked ID queries: See chunked-queries.md


Query Reference

Comparison: equal | notEqual | lessThan | lessThanEqual | greaterThan | greaterThanEqual | between | notBetween String: startsWith | endsWith | contains | search (+ not variants) Null: isNull | isNotNull · Logical: and([...]) | or([...]) Pagination: select | limit | cursorAfter | cursorBefore | orderAsc | orderDesc | orderRandom Timestamp: createdAfter | createdBefore | updatedAfter | updatedBefore Spatial: distanceEqual | distanceLessThan | distanceGreaterThan | intersects | overlaps | touches | crosses (+ not variants)

All prefixed with Query.. Details: query-optimization.md


Operators (Atomic Updates)

data: {
    'likes': Operator.increment(1),
    'tags': Operator.arrayAppend(['trending']),
    'updatedAt': Operator.dateSetNow(),
}

Numeric: increment | decrement | multiply | divide Array: arrayAppend | arrayPrepend | arrayRemove | arrayUnique | arrayIntersect | arrayDiff Other: toggle | stringConcat | stringReplace | dateAddDays | dateSetNow

Details: atomic-operators.md


Column Types

TypeMax CharsIndexingUse
varchar16,383Full (if size < 768)Queryable short strings
text16,383Prefix onlyDescriptions, notes
mediumtext4,194,303Prefix onlyArticles
longtext1,073,741,823Prefix onlyLarge documents

string is deprecated. Use varchar for queryable, text for non-indexed.

Other: integer | float | boolean | datetime | email | url | ip | enum | relationship | point | line | polygon

Details: schema-management.md


Performance

RuleImpact
Cursor pagination10-100x faster than offset
Pagination mixin (Dart)~50 lines saved per datasource
Query.select()12-18x faster for relationships
total: falseEliminates COUNT scan
Indexes100x faster on large tables
OperatorsNo race conditions
Bulk operationsN → 1 request
Delta syncFetches only changed rows

Details: performance.md, pagination-performance.md


Type-Safe SDK Generation

appwrite generate

Generates typed helpers into generated/appwrite/ from your database schema. Autocomplete, compile-time validation, no hand-written types. Regenerate after schema changes.


Authentication

Email/password, OAuth (50+ providers), phone, magic link, anonymous, email OTP, custom token. MFA with TOTP, email, phone, recovery codes. SSR session handling. JWT for functions.

Details: authentication.md | auth-methods.md


Storage

Upload, download, preview with transformations (resize, format conversion), file tokens for shareable URLs. Supports HEIC, AVIF, WebP.

Details: storage-files.md


Realtime

final sub = realtime.subscribe(['databases.db.tables.posts.rows']);
sub.stream.listen((e) => print(e.events));

Channels: account | databases.<DB>.tables.<TABLE>.rows | buckets.<BUCKET>.files

Channel helpers (preferred): Use Channel class for type-safe subscriptions with IDE autocomplete:

import { Client, Realtime, Channel, Query } from "appwrite";
const sub = await realtime.subscribe(
    Channel.tablesdb('<DB>').table('<TABLE>').row(),
    response => console.log(response.payload),
    [Query.equal('status', ['active'])]  // server-side filtering
);

Details: realtime.md


Functions

Init SDK outside handler. Group by domain. Use event triggers, not polling.

Details: functions.md | functions-advanced.md


Transactions

final tx = await tablesDB.createTransaction(ttl: 300);
await tablesDB.createRow(..., transactionId: tx.$id);
await tablesDB.updateTransaction(transactionId: tx.$id, commit: true);

Details: transactions.md


Relationships

await tablesDB.listRows(databaseId: 'db', tableId: 'posts',
    queries: [Query.equal('author.country', 'US'), Query.select(['title', 'author.name'])]);

Types: oneToOne | oneToMany | manyToOne | manyToMany

Details: relationships.md


Permissions

permissions: [
    Permission.read(Role.any()),
    Permission.update(Role.user(userId)),
    Permission.delete(Role.team('admin')),
    Permission.create(Role.label('premium')),
]

Roles: any() | guests() | users() | user(id) | team(id) | team(id, role) | label(name)


Limits

Default page: 25 · Bulk: 1000 rows · Query.equal(): 100 values · Nesting: 3 levels · Queries/req: 100 · Timeout: 15s

Error Codes

400 Bad request · 401 Unauthorized · 403 Forbidden · 404 Not found · 409 Conflict · 429 Rate limited (client SDKs only)

Details: error-handling.md


Anti-Patterns

WrongRightWhy
N+1 queriesQuery.select(['col', 'relation.col'])Eliminates extra round-trips
Read-modify-writeOperator.increment()Race condition
Large offsetsQuery.cursorAfter(id)O(n) vs O(1)
Skip totalstotal: falseEliminates COUNT scan
Missing indexesCreate for queried columnsQueries scan entire table
SDK init inside handlerInit outside for warm reuseRepeated setup on every call
Hardcoded secretsEnvironment variablesSecurity risk
PollingRealtime or event triggersWasted executions
Client-side filteringRealtime queriesServer does the work
Raw channel stringsChannel helpersTypos, no autocomplete
ColumnStringColumnVarchar or ColumnTextstring type is deprecated
Hand-writing typesappwrite generateSchema drift, no autocomplete
databases.listDocuments()tablesDB.listRows()Deprecated API
Custom ID generatorsID.unique()Overflow risk, info leakage
Full re-fetch every syncQuery.updatedAfter() + per-table timestampsWastes bandwidth, slow
Loop with createRow()createRows() bulkN requests vs 1

Cost Optimization

  1. Query.select() — reduces bandwidth
  2. Cursor pagination + total: false — fastest queries
  3. Realtime over polling — one connection vs repeated calls
  4. Batch operations — 1 execution vs N
  5. WebP at quality 80 — smallest files, universal support
  6. Init outside handler — fewer cold starts
  7. Budget cap — Organization → Billing → Budget cap

Details: cost-optimization.md


Reference Files

Data: schema-management · query-optimization · atomic-operators · relationships · transactions · bulk-operations · chunked-queries Performance: performance · pagination-performance · cost-optimization Auth: authentication · auth-methods · teams Services: storage-files · functions · functions-advanced · realtime · messaging · webhooks · avatars · graphql · locale Platform: error-handling · limits · health · self-hosting · self-hosting-ops


Resources

Docs: https://appwrite.io/docs · API: https://appwrite.io/docs/references · SDKs: https://github.com/appwrite

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

Glin Profanity

Profanity detection and content moderation library with leetspeak, Unicode homoglyph, and ML-powered detection. Use when filtering user-generated content, moderating comments, checking text for profanity, censoring messages, or building content moderation into applications. Supports 24 languages.

Registry SourceRecently Updated
1.5K1Profile unavailable
Coding

joinquant

聚宽量化交易平台 - 提供A股、期货、基金数据查询,事件驱动策略回测,支持在线研究与模拟实盘。

Registry SourceRecently Updated
730Profile unavailable
Coding

错敏信息检测

基于FastAPI的文本错敏信息检测服务,识别敏感词、错别字及规范表述问题,提供RESTful API接口调用。

Registry SourceRecently Updated
1930Profile unavailable
Coding

Scrapling Fetch

支持自动绕过 Cloudflare Turnstile 和微信公众号反爬机制的网页内容抓取工具,输出干净Markdown或纯文本。

Registry SourceRecently Updated
1610Profile unavailable