Dart

by appwriteab3c90b37c95No license10 starsListed Oct 8, 2026Updated Oct 8, 2026Repository updated 7 weeks ago

Appwrite Dart SDK skill. Use when building Flutter apps (mobile, web, desktop) or server-side Dart applications with Appwrite. Covers client-side auth (email, OAuth), database queries, file uploads with native file handling, real-time subscriptions, and server-side admin via API keys for user management, database administration, storage, and functions.

Instructions onlySoftware Development
AI-generated overview

Reference guide for building Appwrite apps in Dart and Flutter, covering auth, database, storage, realtime and functions.

What it does
This skill is a documentation-style reference for the Appwrite Dart SDK. It provides code examples for client-side Flutter and server-side Dart setup, authentication, database and table operations, queries, file storage, teams, realtime subscriptions, serverless functions and SSR session handling. It also documents permissions, roles and error handling conventions.
When to use it
Use it when writing or reviewing Dart or Flutter code that talks to Appwrite, such as adding email or OAuth login, querying tables, uploading files, subscribing to realtime updates, or implementing server-side admin and SSR authentication.
Requirements
No scripts are shipped; it is instructions and code examples only. Using the examples requires the Appwrite Dart SDK packages (appwrite for Flutter, dart_appwrite for server-side Dart), a Dart or Flutter toolchain, an Appwrite project endpoint and project ID, and for server-side use an Appwrite API key.

Appwrite Dart SDK

Installation

bash
# Flutter (client-side)flutter pub add appwrite
# Dart (server-side)dart pub add dart_appwrite

Setting Up the Client

Client-side (Flutter)

dart
import 'package:appwrite/appwrite.dart';
final client = Client()    .setEndpoint('https://<REGION>.cloud.appwrite.io/v1')    .setProject('[PROJECT_ID]');

Server-side (Dart)

dart
import 'package:dart_appwrite/dart_appwrite.dart';
final client = Client()    .setEndpoint('https://<REGION>.cloud.appwrite.io/v1')    .setProject(Platform.environment['APPWRITE_PROJECT_ID']!)    .setKey(Platform.environment['APPWRITE_API_KEY']!);

Code Examples

Authentication (client-side)

dart
final account = Account(client);
// Signupawait account.create(userId: ID.unique(), email: '[email protected]', password: 'password123', name: 'User Name');
// Loginfinal session = await account.createEmailPasswordSession(email: '[email protected]', password: 'password123');
// OAuth loginawait account.createOAuth2Session(provider: OAuthProvider.google);
// Get current userfinal user = await account.get();
// Logoutawait account.deleteSession(sessionId: 'current');

User Management (server-side)

dart
final users = Users(client);
// Create userfinal user = await users.create(userId: ID.unique(), email: '[email protected]', password: 'password123', name: 'User Name');
// List usersfinal list = await users.list(queries: [Query.limit(25)]);
// Get userfinal fetched = await users.get(userId: '[USER_ID]');
// Delete userawait users.delete(userId: '[USER_ID]');

Database Operations

Note: Use TablesDB (not the deprecated Databases class) for all new code. Only use Databases if the existing codebase already relies on it or the user explicitly requests it.

Tip: Prefer named parameters (e.g., databaseId: '...') for all SDK method calls. Only use positional arguments if the existing codebase already uses them or the user explicitly requests it.

dart
final tablesDB = TablesDB(client);
// Create database (server-side only)final db = await tablesDB.create(databaseId: ID.unique(), name: 'My Database');
// Create table (server-side only)final col = await tablesDB.createTable(databaseId: '[DATABASE_ID]', tableId: ID.unique(), name: 'My Table');
// Create rowfinal doc = await tablesDB.createRow(    databaseId: '[DATABASE_ID]',    tableId: '[TABLE_ID]',    rowId: ID.unique(),    data: {'title': 'Hello', 'done': false},);
// Query rowsfinal results = await tablesDB.listRows(    databaseId: '[DATABASE_ID]',    tableId: '[TABLE_ID]',    queries: [Query.equal('done', false), Query.limit(10)],);
// Get rowfinal row = await tablesDB.getRow(databaseId: '[DATABASE_ID]', tableId: '[TABLE_ID]', rowId: '[ROW_ID]');
// Update rowawait tablesDB.updateRow(    databaseId: '[DATABASE_ID]',    tableId: '[TABLE_ID]',    rowId: '[ROW_ID]',    data: {'done': true},);
// Delete rowawait tablesDB.deleteRow(    databaseId: '[DATABASE_ID]',    tableId: '[TABLE_ID]',    rowId: '[ROW_ID]',);
String Column Types

Note: The legacy string type is deprecated. Use explicit column types for all new columns.

TypeMax charactersIndexingStorage
varchar16,383Full index (if size ≤ 768)Inline in row
text16,383Prefix onlyOff-page
mediumtext4,194,303Prefix onlyOff-page
longtext1,073,741,823Prefix onlyOff-page
  • varchar is stored inline and counts towards the 64 KB row size limit. Prefer for short, indexed fields like names, slugs, or identifiers.
  • text, mediumtext, and longtext are stored off-page (only a 20-byte pointer lives in the row), so they don't consume the row size budget. size is not required for these types.
dart
// Create table with explicit string column typesawait tablesDB.createTable(    databaseId: '[DATABASE_ID]',    tableId: ID.unique(),    name: 'articles',    columns: [        {'key': 'title',    'type': 'varchar',    'size': 255, 'required': true},   // inline, fully indexable        {'key': 'summary',  'type': 'text',                    'required': false},  // off-page, prefix index only        {'key': 'body',     'type': 'mediumtext',              'required': false},  // up to ~4 M chars        {'key': 'raw_data', 'type': 'longtext',                'required': false},  // up to ~1 B chars    ],);

Query Methods

dart
// FilteringQuery.equal('field', 'value')             // == (or pass list for IN)Query.notEqual('field', 'value')          // !=Query.lessThan('field', 100)              // <Query.lessThanEqual('field', 100)         // <=Query.greaterThan('field', 100)           // >Query.greaterThanEqual('field', 100)      // >=Query.between('field', 1, 100)            // 1 <= field <= 100Query.isNull('field')                     // is nullQuery.isNotNull('field')                  // is not nullQuery.startsWith('field', 'prefix')       // starts withQuery.endsWith('field', 'suffix')         // ends withQuery.contains('field', 'sub')            // containsQuery.search('field', 'keywords')         // full-text search (requires index)
// SortingQuery.orderAsc('field')Query.orderDesc('field')
// PaginationQuery.limit(25)                           // max rows (default 25, max 100)Query.offset(0)                           // skip N rowsQuery.cursorAfter('[ROW_ID]')             // cursor pagination (preferred)Query.cursorBefore('[ROW_ID]')
// Selection & LogicQuery.select(['field1', 'field2'])        // return only specified fieldsQuery.or([Query.equal('a', 1), Query.equal('b', 2)])   // ORQuery.and([Query.greaterThan('age', 18), Query.lessThan('age', 65)])  // AND (default)

File Storage

dart
final storage = Storage(client);
// Upload filefinal file = await storage.createFile(    bucketId: '[BUCKET_ID]',    fileId: ID.unique(),    file: InputFile.fromPath(path: '/path/to/file.png', filename: 'file.png'),);
// Get file previewfinal preview = storage.getFilePreview(bucketId: '[BUCKET_ID]', fileId: '[FILE_ID]', width: 300, height: 300);
// List filesfinal files = await storage.listFiles(bucketId: '[BUCKET_ID]');
// Delete fileawait storage.deleteFile(bucketId: '[BUCKET_ID]', fileId: '[FILE_ID]');
InputFile Factory Methods
dart
// Client-side (Flutter)InputFile.fromPath(path: '/path/to/file.png', filename: 'file.png')    // from pathInputFile.fromBytes(bytes: uint8List, filename: 'file.png')            // from Uint8List
// Server-side (Dart)InputFile.fromPath(path: '/path/to/file.png', filename: 'file.png')InputFile.fromBytes(bytes: uint8List, filename: 'file.png')

Teams

dart
final teams = Teams(client);
// Create teamfinal team = await teams.create(teamId: ID.unique(), name: 'Engineering');
// List teamsfinal list = await teams.list();
// Create membership (invite user by email)final membership = await teams.createMembership(    teamId: '[TEAM_ID]',    roles: ['editor'],    email: '[email protected]',);
// List membershipsfinal members = await teams.listMemberships(teamId: '[TEAM_ID]');
// Update membership rolesawait teams.updateMembership(teamId: '[TEAM_ID]', membershipId: '[MEMBERSHIP_ID]', roles: ['admin']);
// Delete teamawait teams.delete(teamId: '[TEAM_ID]');

Role-based access: Use Role.team('[TEAM_ID]') for all team members or Role.team('[TEAM_ID]', 'editor') for a specific team role when setting permissions.

Real-time Subscriptions (client-side)

dart
final realtime = Realtime(client);
// Subscribe to row changesfinal subscription = realtime.subscribe([    Channel.tablesdb('[DATABASE_ID]').table('[TABLE_ID]').row(),]);subscription.stream.listen((response) {    print(response.events);   // e.g. ['tablesdb.*.tables.*.rows.*.create']    print(response.payload);  // the affected resource});
// Subscribe to multiple channelsfinal multi = realtime.subscribe([    Channel.tablesdb('[DATABASE_ID]').table('[TABLE_ID]').row(),    Channel.bucket('[BUCKET_ID]').file(),]);
// Cleanupsubscription.close();

Available channels:

ChannelDescription
accountChanges to the authenticated user's account
tablesdb.[DB_ID].tables.[TABLE_ID].rowsAll rows in a table
tablesdb.[DB_ID].tables.[TABLE_ID].rows.[ROW_ID]A specific row
buckets.[BUCKET_ID].filesAll files in a bucket
buckets.[BUCKET_ID].files.[FILE_ID]A specific file
teamsChanges to teams the user belongs to
teams.[TEAM_ID]A specific team
membershipsThe user's team memberships
memberships.[MEMBERSHIP_ID]A specific membership
functions.[FUNCTION_ID].executionsFunction execution updates

Response fields: events (array), payload (resource), channels (matched), timestamp (ISO 8601).

Serverless Functions (server-side)

dart
final functions = Functions(client);
// Execute functionfinal execution = await functions.createExecution(functionId: '[FUNCTION_ID]', body: '{"key": "value"}');
// List executionsfinal executions = await functions.listExecutions(functionId: '[FUNCTION_ID]');
Writing a Function Handler (Dart runtime)
dart
// lib/main.dart — Appwrite Function entry pointFuture<dynamic> main(final context) async {    // context.req.body        — raw body (String)    // context.req.bodyJson    — parsed JSON (Map or null)    // context.req.headers     — headers (Map)    // context.req.method      — HTTP method    // context.req.path        — URL path    // context.req.query       — query params (Map)
    context.log('Processing: ${context.req.method} ${context.req.path}');
    if (context.req.method == 'GET') {        return context.res.json({'message': 'Hello from Appwrite Function!'});    }
    return context.res.json({'success': true});      // JSON    // return context.res.text('Hello');              // plain text    // return context.res.empty();                    // 204    // return context.res.redirect('https://...');    // 302}

Server-Side Rendering (SSR) Authentication

SSR apps using server-side Dart (Dart Frog, Shelf, etc.) use the server SDK (dart_appwrite) to handle auth. You need two clients:

  • Admin client — uses an API key, creates sessions, bypasses rate limits (reusable singleton)
  • Session client — uses a session cookie, acts on behalf of a user (create per-request, never share)
dart
import 'package:dart_appwrite/dart_appwrite.dart';
// Admin client (reusable)final adminClient = Client()    .setEndpoint('https://<REGION>.cloud.appwrite.io/v1')    .setProject('[PROJECT_ID]')    .setKey(Platform.environment['APPWRITE_API_KEY']!);
// Session client (create per-request)final sessionClient = Client()    .setEndpoint('https://<REGION>.cloud.appwrite.io/v1')    .setProject('[PROJECT_ID]');
final session = request.cookies['a_session_[PROJECT_ID]'];if (session != null) {    sessionClient.setSession(session);}
Email/Password Login
dart
final account = Account(adminClient);final session = await account.createEmailPasswordSession(    email: body['email'],    password: body['password'],);
// Cookie name must be a_session_<PROJECT_ID>response.headers.add('Set-Cookie',    'a_session_[PROJECT_ID]=${session.secret}; '    'HttpOnly; Secure; SameSite=Strict; '    'Expires=${HttpDate.format(DateTime.parse(session.expire))}; Path=/');
Authenticated Requests
dart
final session = request.cookies['a_session_[PROJECT_ID]'];if (session == null) {    return Response(statusCode: 401, body: 'Unauthorized');}
final sessionClient = Client()    .setEndpoint('https://<REGION>.cloud.appwrite.io/v1')    .setProject('[PROJECT_ID]')    .setSession(session);
final account = Account(sessionClient);final user = await account.get();
OAuth2 SSR Flow
dart
// Step 1: Redirect to OAuth providerfinal account = Account(adminClient);final redirectUrl = await account.createOAuth2Token(    provider: OAuthProvider.github,    success: 'https://example.com/oauth/success',    failure: 'https://example.com/oauth/failure',);return Response(statusCode: 302, headers: {'Location': redirectUrl});
// Step 2: Handle callback — exchange token for sessionfinal account = Account(adminClient);final session = await account.createSession(    userId: request.uri.queryParameters['userId']!,    secret: request.uri.queryParameters['secret']!,);// Set session cookie as above

Cookie security: Always use HttpOnly, Secure, and SameSite=Strict to prevent XSS. The cookie name must be a_session_<PROJECT_ID>.

Forwarding user agent: Call sessionClient.setForwardedUserAgent(request.headers['user-agent']) to record the end-user's browser info for debugging and security.

Error Handling

dart
import 'package:appwrite/appwrite.dart';// AppwriteException is included in the main import
try {    final row = await tablesDB.getRow(databaseId: '[DATABASE_ID]', tableId: '[TABLE_ID]', rowId: '[ROW_ID]');} on AppwriteException catch (e) {    print(e.message);    // human-readable message    print(e.code);       // HTTP status code (int)    print(e.type);       // error type (e.g. 'document_not_found')    print(e.response);   // full response body (Map)}

Common error codes:

CodeMeaning
401Unauthorized — missing or invalid session/API key
403Forbidden — insufficient permissions
404Not found — resource does not exist
409Conflict — duplicate ID or unique constraint
429Rate limited — too many requests

Permissions & Roles (Critical)

Appwrite uses permission strings to control access to resources. Each permission pairs an action (read, update, delete, create, or write which grants create + update + delete) with a role target. By default, no user has access unless permissions are explicitly set at the row/file level or inherited from the table/bucket settings. Permissions are arrays of strings built with the Permission and Role helpers.

dart
import 'package:appwrite/appwrite.dart';// Permission and Role are included in the main package import

Database Row with Permissions

dart
final doc = await tablesDB.createRow(    databaseId: '[DATABASE_ID]',    tableId: '[TABLE_ID]',    rowId: ID.unique(),    data: {'title': 'Hello World'},    permissions: [        Permission.read(Role.user('[USER_ID]')),     // specific user can read        Permission.update(Role.user('[USER_ID]')),   // specific user can update        Permission.read(Role.team('[TEAM_ID]')),     // all team members can read        Permission.read(Role.any()),                 // anyone (including guests) can read    ],);

File Upload with Permissions

dart
final file = await storage.createFile(    bucketId: '[BUCKET_ID]',    fileId: ID.unique(),    file: InputFile.fromPath(path: '/path/to/file.png', filename: 'file.png'),    permissions: [        Permission.read(Role.any()),        Permission.update(Role.user('[USER_ID]')),        Permission.delete(Role.user('[USER_ID]')),    ],);

When to set permissions: Set row/file-level permissions when you need per-resource access control. If all rows in a table share the same rules, configure permissions at the table/bucket level and leave row permissions empty.

Common mistakes:

  • Forgetting permissions — the resource becomes inaccessible to all users (including the creator)
  • Role.any() with write/update/delete — allows any user, including unauthenticated guests, to modify or remove the resource
  • Permission.read(Role.any()) on sensitive data — makes the resource publicly readable

Source and attribution

Source:appwrite/claude-plugininskills/dartat commitab3c90b

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal