From 6c7685e6059b8b24eb8b8d0639dbc595f33fa273 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Mon, 25 May 2026 20:46:47 +0530 Subject: [PATCH 01/61] Add React library docs and announcement blog post Adds /docs/products/auth/react hub covering the provider, hooks, server helpers, handler routes, and OAuth flow. Rewrites the React, Next.js, and TanStack Start quickstarts to use @appwrite.io/react. Adds a launch blog post under blog/post/announcing-appwrite-react-library and a new "React library" entry in the Auth sidebar. Updates /docs/sdks to list the package. --- .../+page.markdoc | 133 ++++++ src/routes/docs/products/auth/+layout.svelte | 5 + .../docs/products/auth/react/+page.markdoc | 377 ++++++++++++++++++ .../docs/quick-starts/nextjs/+page.markdoc | 295 +++++++++----- .../docs/quick-starts/react/+page.markdoc | 190 +++++---- .../quick-starts/tanstack-start/+page.markdoc | 260 +++++++----- src/routes/docs/sdks/+page.markdoc | 6 + 7 files changed, 981 insertions(+), 285 deletions(-) create mode 100644 src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc create mode 100644 src/routes/docs/products/auth/react/+page.markdoc diff --git a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc new file mode 100644 index 00000000000..69f02839e76 --- /dev/null +++ b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc @@ -0,0 +1,133 @@ +--- +layout: post +title: "Announcing the Appwrite React library" +description: A small set of React hooks and SSR adapters that take the busywork out of wiring Appwrite Auth into Vite, Next.js, and TanStack Start apps. +date: 2026-05-25 +cover: /images/blog/announcing-appwrite-react-library/cover.avif +timeToRead: 5 +author: atharva +category: announcement, authentication +faqs: + - question: 'What is the Appwrite React library?' + answer: 'It is an official React package that wraps the Appwrite Web SDK with a `Provider` and hooks for auth state. It also ships SSR adapters for Next.js and TanStack Start so the same hooks work in server-rendered apps. See the [React library docs](/docs/products/auth/react).' + - question: 'Do I need this if I already use the Appwrite Web SDK?' + answer: 'No, the Web SDK alone still works. The library is for teams who want pre-built hooks, less boilerplate around session hydration, and a turnkey SSR auth flow. If your app is small or fully client-rendered, the Web SDK on its own is fine.' + - question: 'Which React versions are supported?' + answer: 'React 18 and React 19, on both client-rendered apps and SSR frameworks. Next.js 15+ and TanStack Start are supported out of the box.' + - question: 'How does SSR auth work under the hood?' + answer: 'You mount one handler route per framework. The handler creates sessions with a server API key and writes an HTTP-only cookie. On the server, helpers read the cookie and return the user; on the client, the same cookie hydrates the Web SDK so hooks return the user without an extra round trip.' + - question: 'Does the library cover more than authentication?' + answer: 'Not yet. The first release focuses on the auth surface (sign-up, sign-in, sign-out, OAuth, current user). Database and storage hooks are on the roadmap.' + - question: 'Where do I start?' + answer: 'Pick the framework you are using: [Vite React](/docs/quick-starts/react), [Next.js](/docs/quick-starts/nextjs), or [TanStack Start](/docs/quick-starts/tanstack-start). Each quickstart walks through install, configuration, and a working sign-up flow.' +--- + +Every React developer who has wired Appwrite into a project knows the drill. You install the Web SDK, write a small `appwrite.ts` file with a `Client` and an `Account`, and then build the same `useUser` hook and sign-in form you have built for every other project. For client-only apps that is fine, but the moment SSR enters the picture (`cookies()` in Next.js, server functions in TanStack Start) you also start hand-rolling session cookies, server helpers, and the `setSession` plumbing that hydrates the client from the request. + +Today, we are releasing the [Appwrite React library](/docs/products/auth/react), an official package that gives you that whole layer out of the box. + +# The provider and hooks + +The library exposes a single `AppwriteProvider` and five auth hooks: + +- `useAuth` for the combined user, sign-in, sign-up, and sign-out surface +- `useUser` for the current authenticated user +- `useSignIn` for email/password and OAuth sign-in +- `useSignUp` for account creation +- `useSignOut` for ending the current session + +It is built on top of the existing [Appwrite Web SDK](/docs/sdks) and uses TanStack Query underneath, so cached user state stays in sync across components automatically. + +What makes it different from a hand-rolled `useUser` is what happens on the server. The library ships dedicated entrypoints for Next.js App Router and TanStack Start that handle the cookie, hydration, and admin-client wiring for you, so the hooks behave the same in a Vite SPA as they do in a server-rendered page. + +# Client-side setup + +For a Vite app, setup is two imports. Wrap the tree with the provider, then call `useAuth` wherever you need it. + +```tsx +// main.tsx +import { AppwriteProvider } from "@appwrite.io/react"; + + + +; +``` + +With the provider in place, every component can pull the current user, sign-in, sign-up, and sign-out methods from a single hook. + +```tsx +// App.tsx +import { useAuth } from "@appwrite.io/react"; + +const { user, signIn, signOut } = useAuth(); +``` + +That is the entire client setup. The library handles the service file, the initial account fetching on mount, and the auth context that you would otherwise write by hand. The full walkthrough lives in the [Vite React quickstart](/docs/quick-starts/react). + +# Server-side rendering + +For server-rendered React, the package adds three pieces: + +- A handler route that processes sign-in, sign-up, sign-out, and OAuth callback requests on your server. +- Server helpers that resolve the current user, session, or session-scoped client from the request cookie. +- An SSR mode on the provider that hydrates the client with the server-side session, so the first paint already knows the user. + +Concretely, in a Next.js layout, you read the cookie server-side, pass the value through the provider, and the client hooks pick it up. + +```tsx +// app/layout.tsx +const helpers = createNextServerHelpers(appwrite); +const session = await helpers.readSessionCookie(); + +return {children}; +``` + +The same helpers can be called inside any server component to fetch the user before the page is sent to the browser. + +```tsx +// app/page.tsx +const user = await helpers.getLoggedInUser(); +``` + +The same flow on TanStack Start runs through `createServerFn` and `Route.useLoaderData()`. The hooks themselves do not change. + +# Session client + +For per-request operations on behalf of the signed-in user, the framework helpers expose `createSessionClient`. It returns a `node-appwrite` client already authenticated with the request cookie, so server components and loaders can act as the user without re-implementing session handling. + +```ts +const helpers = createNextServerHelpers(appwrite); +const session = await helpers.createSessionClient(); + +if (session) { + const user = await session.account.get(); +} +``` + +# Admin client + +Server entrypoints also expose `createAdminClient`, which returns a `node-appwrite` client authenticated with your project API key. It is the same client you would write yourself, just with the environment wiring done for you, so the rest of your server code keeps using the official Node SDK. + +```ts +const admin = createAdminClient({ + ...appwrite, + apiKey: process.env.APPWRITE_API_KEY!, +}); + +const users = await admin.account.list(); +``` + +# Where to start + +Three quickstarts ship alongside the library: + +- [Vite React](/docs/quick-starts/react) for client-rendered apps +- [Next.js App Router](/docs/quick-starts/nextjs) for server-rendered React on Next.js +- [TanStack Start](/docs/quick-starts/tanstack-start) for server-rendered React on TanStack Start + +Each one ends with a working sign-up, sign-in, and sign-out flow. From there, the [React library docs](/docs/products/auth/react) cover the hooks, the server helpers, OAuth, and the handler configuration in depth. + +We would love to hear what you build with it. Drop into the [Appwrite Discord](https://appwrite.io/discord) and tell us how the SSR story feels in your framework of choice. diff --git a/src/routes/docs/products/auth/+layout.svelte b/src/routes/docs/products/auth/+layout.svelte index 799c2019496..67bc9b0f3ff 100644 --- a/src/routes/docs/products/auth/+layout.svelte +++ b/src/routes/docs/products/auth/+layout.svelte @@ -104,6 +104,11 @@ label: 'SSR login', href: '/docs/products/auth/server-side-rendering' }, + { + label: 'React library', + href: '/docs/products/auth/react', + new: isNewUntil('30 June 2026') + }, { label: 'Custom token login', href: '/docs/products/auth/custom-token' diff --git a/src/routes/docs/products/auth/react/+page.markdoc b/src/routes/docs/products/auth/react/+page.markdoc new file mode 100644 index 00000000000..be70c3b9de0 --- /dev/null +++ b/src/routes/docs/products/auth/react/+page.markdoc @@ -0,0 +1,377 @@ +--- +layout: article +title: React library +description: Add authentication to React apps with Appwrite's official React library. Supports client-side React, Next.js, and TanStack Start with a single provider and a small set of hooks. +--- + +The Appwrite React library is a thin layer over the [Web SDK](/docs/sdks) that exposes a provider and a small set of hooks for authentication operations and current user state. It works in both client-rendered React apps and server-rendered apps on Next.js and TanStack Start. + +# Why use it {% #why %} + +- **SSR auth without boilerplate.** Drop in one handler route per framework and skip the days normally spent writing cookie logic, session sync, and server/client hydration. +- **Consistent user state across server and client.** Server components, loaders, and client hooks return the same authenticated user, removing the need to reconcile auth state across the render boundary. +- **Server-side access when you need it.** Read the current user, create per-request session clients, or reach for an admin client without hand-wiring the Node SDK on every route. + +# Install {% #install %} + +Install the library along with the **Appwrite Web SDK** and **TanStack Query** packages. + +```sh +npm install @appwrite.io/react appwrite @tanstack/react-query +``` + +For SSR apps on Next.js or TanStack Start, also install `node-appwrite`. The SSR handlers create sessions with a server API key. + +```sh +npm install @appwrite.io/react appwrite node-appwrite @tanstack/react-query +``` + +# Pick your framework {% #frameworks %} + +{% cards %} +{% cards_item href="/docs/quick-starts/react" title="Client-side React" %} +For Vite and other client-rendered React apps. +{% /cards_item %} +{% cards_item href="/docs/quick-starts/nextjs" title="Next.js" %} +For server-rendered apps on the Next.js App Router. +{% /cards_item %} +{% cards_item href="/docs/quick-starts/tanstack-start" title="TanStack Start" %} +For server-rendered apps on TanStack Start. +{% /cards_item %} +{% /cards %} + +# The provider {% #provider %} + +Every app starts with an `AppwriteProvider`. In a CSR app, only `endpoint` and `projectId` are required. + +```tsx +import { AppwriteProvider } from "@appwrite.io/react"; + + + +; +``` + +In an SSR app, pass an `ssr` prop with the session secret read from the server-side cookie and the path your handlers are mounted at. + +```tsx + + {children} + +``` + +When `ssr` is set, sign-in, sign-up, and sign-out mutations route through your handler. The underlying Web SDK is hydrated with the session secret on first render so authenticated reads do not need a round trip. + +# Hooks {% #hooks %} + +The library exports one combined hook and four focused mutation hooks. All hooks share the same TanStack Query cache, so updating user state from any of them reflects everywhere. + +## useAuth {% #use-auth %} + +```tsx +import { useAuth } from "@appwrite.io/react"; + +const { user, isLoading, error, signIn, signUp, signOut } = useAuth(); +``` + +Returns: + +| Field | Type | Description | +| --- | --- | --- | +| `user` | `Models.User \| null \| undefined` | The current user, or `null` if signed out. `undefined` while loading. | +| `isLoading` | `boolean` | True while the initial user fetch is in flight. | +| `error` | `Error \| null` | First error from the user query or any mutation. | +| `signIn` | `ReturnType` | Sign-in mutation handle. | +| `signUp` | `ReturnType` | Sign-up mutation handle. | +| `signOut` | `ReturnType` | Sign-out mutation handle. | + +## useUser {% #use-user %} + +```tsx +import { useUser } from "@appwrite.io/react"; + +const { user, isLoading, error } = useUser(); +``` + +Returns: + +| Field | Type | Description | +| --- | --- | --- | +| `user` | `Models.User \| null \| undefined` | The current user, or `null` if signed out. `undefined` while loading. | +| `isLoading` | `boolean` | True while the user is being fetched. | +| `error` | `Error \| null` | Error from the fetch, if one occurred. | + +## useSignIn {% #use-sign-in %} + +```tsx +const { emailPassword, oAuth, isPending, error } = useSignIn(); + +emailPassword({ email, password, onSuccess, onError }); +oAuth({ provider: OAuthProvider.Google, successUrl, failureUrl, scopes }); +``` + +Returns: + +| Field | Type | Description | +| --- | --- | --- | +| `emailPassword` | `function` | Trigger an email and password sign-in. | +| `oAuth` | `function` | Trigger an OAuth sign-in. | +| `isPending` | `boolean` | True while an email and password sign-in is in flight. | +| `error` | `Error \| null` | Error from the last email and password sign-in attempt. | + +Parameters for `emailPassword`: + +| Parameter | Required | Description | +| --- | --- | --- | +| `email` | Yes | User's email address. | +| `password` | Yes | User's password. | +| `onSuccess` | No | Callback invoked with the signed-in user. | +| `onError` | No | Callback invoked with the thrown error. | + +Parameters for `oAuth`: + +| Parameter | Required | Description | +| --- | --- | --- | +| `provider` | Yes | An `OAuthProvider` value re-exported by the library. | +| `successUrl` | No | URL to redirect to after successful login (CSR only). | +| `failureUrl` | No | URL to redirect to after a failed attempt. | +| `scopes` | No | Provider-specific OAuth scopes to request. | +| `onError` | No | Callback invoked if the request fails before redirect. | + +In SSR mode the success URL is fixed to the handler callback. The final redirect after that callback is controlled by the `redirects.success` config on the handler. + +## useSignUp {% #use-sign-up %} + +```tsx +const { emailPassword, isPending, error } = useSignUp(); + +emailPassword({ email, password, name, userId, onSuccess, onError }); +``` + +Returns: + +| Field | Type | Description | +| --- | --- | --- | +| `emailPassword` | `function` | Create an account with email and password, then sign the user in. | +| `isPending` | `boolean` | True while the sign-up is in flight. | +| `error` | `Error \| null` | Error from the last sign-up attempt. | + +Parameters for `emailPassword`: + +| Parameter | Required | Description | +| --- | --- | --- | +| `email` | Yes | New user's email address. | +| `password` | Yes | New user's password. | +| `name` | No | Display name for the user. | +| `userId` | No | Custom user ID. Defaults to `ID.unique()`. | +| `onSuccess` | No | Callback invoked with the created user. | +| `onError` | No | Callback invoked with the thrown error. | + +## useSignOut {% #use-sign-out %} + +```tsx +const { signOut, isPending, error } = useSignOut(); + +signOut({ onSuccess, onError }); +``` + +Returns: + +| Field | Type | Description | +| --- | --- | --- | +| `signOut` | `function` | End the current user's session. | +| `isPending` | `boolean` | True while the sign-out is in flight. | +| `error` | `Error \| null` | Error from the last sign-out attempt. | + +Parameters for `signOut`: + +| Parameter | Required | Description | +| --- | --- | --- | +| `onSuccess` | No | Callback invoked after the session is destroyed. | +| `onError` | No | Callback invoked with the thrown error. | + +After a successful sign-out, all cached auth queries are dropped and the local Web SDK client is reset. On Next.js, call `router.refresh()` from `onSuccess` to re-render server components with the cleared cookie. On TanStack Start, call `router.invalidate()`. + +## useAppwrite {% #use-appwrite %} + +```tsx +import { useAppwrite } from "@appwrite.io/react"; + +const { client, account, tablesDB, storage, teams, ssr } = useAppwrite(); +``` + +Returns the underlying provider context with every Appwrite Web SDK service instance bound to the configured client. Use it when you need direct access to a service the higher-level hooks do not wrap (databases, storage, messaging, realtime, and so on). + +Returns: + +| Field | Type | Description | +| --- | --- | --- | +| `client` | `Client` | The Appwrite Web SDK `Client` configured by the provider. | +| `account` | `Account` | Web SDK `Account` service. | +| `avatars` | `Avatars` | Web SDK `Avatars` service. | +| `functions` | `Functions` | Web SDK `Functions` service. | +| `graphql` | `Graphql` | Web SDK `Graphql` service. | +| `locale` | `Locale` | Web SDK `Locale` service. | +| `messaging` | `Messaging` | Web SDK `Messaging` service. | +| `presences` | `Presences` | Web SDK `Presences` service. | +| `realtime` | `Realtime` | Web SDK `Realtime` service. | +| `storage` | `Storage` | Web SDK `Storage` service. | +| `tablesDB` | `TablesDB` | Web SDK `TablesDB` service. | +| `teams` | `Teams` | Web SDK `Teams` service. | +| `authenticated` | `boolean` | Whether the provider currently considers a user signed in. | +| `setAuthenticated` | `Dispatch>` | Update the authenticated flag manually. | +| `ssr.enabled` | `boolean` | Whether the provider was mounted with the `ssr` prop. | +| `ssr.basePath` | `string` | Mount path of the handler routes. | +| `ssr.session` | `string \| null` | Session secret read from the server cookie. | + +Throws if called outside an `AppwriteProvider`. + +# Server helpers {% #server-helpers %} + +The library ships server entrypoints scoped per framework. Each helper exposes the same surface, differing only in how it reads the request cookie. + +```ts +// Next.js (App Router) +import { createNextServerHelpers } from "@appwrite.io/react/server/next"; + +// TanStack Start +import { createTanStackServerHelpers } from "@appwrite.io/react/server/tanstack"; +``` + +Both return an object with: + +| Method | Returns | Use it for | +| --- | --- | --- | +| `readSessionCookie()` | `string \| undefined` (sync on TanStack, async on Next.js) | The session secret. Pass it into `AppwriteProvider`'s `ssr.session` prop. | +| `getLoggedInUser()` | `Models.User \| null` | The current user, fetched via the cookie. Returns `null` on 401. | +| `getSession()` | `Models.Session \| null` | The current session row. | +| `createSessionClient()` | `{ client, account } \| null` | A `node-appwrite` client authenticated as the cookie's user, or `null` if no cookie. | + +## Session client {% #session-client %} + +For per-request operations scoped to the current user (reading their data, calling APIs on their behalf) call `createSessionClient` from the framework helper. It returns a `node-appwrite` client already authenticated with the session cookie, ready to use in server components, loaders, and server functions. + +```ts +import { createNextServerHelpers } from "@appwrite.io/react/server/next"; + +const helpers = createNextServerHelpers({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, +}); + +const session = await helpers.createSessionClient(); + +if (session) { + const user = await session.account.get(); +} +``` + +## Admin client {% #admin-client %} + +For privileged operations (creating users, listing sessions, managing teams) import `createAdminClient` from the framework-specific server entrypoint. It returns a `node-appwrite` client authenticated with your API key. + +```ts +import { createAdminClient } from "@appwrite.io/react/server/next"; + +const admin = createAdminClient({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + apiKey: process.env.APPWRITE_API_KEY!, +}); + +const users = await admin.account; // node-appwrite Account instance +``` + +Never import any `@appwrite.io/react/server/*` module from client code: the entrypoints are marked `server-only` and will throw if bundled into the browser. + +# Handler routes {% #handlers %} + +The SSR mutations (`sign-in`, `sign-up`, `sign-out`, `oauth/callback`, `oauth/failure`) live behind a handler route you mount once per app. The handler reads the request, talks to Appwrite with the server API key, and writes the session cookie back. + +## Next.js {% #handler-next %} + +```ts +// app/api/appwrite/[...appwrite]/route.ts +import { createAppwriteHandlers } from "@appwrite.io/react/handlers/next"; + +export const { GET, POST } = createAppwriteHandlers({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: "/api/appwrite", +}); +``` + +## TanStack Start {% #handler-tanstack %} + +```ts +// src/routes/api/appwrite/$.ts +import { createFileRoute } from "@tanstack/react-router"; +import { createAppwriteHandlers } from "@appwrite.io/react/handlers/tanstack"; + +export const Route = createFileRoute("/api/appwrite/$")({ + server: { + handlers: createAppwriteHandlers({ + endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT, + projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: "/api/appwrite", + }), + }, +}); +``` + +## Cookie and redirect options {% #handler-options %} + +Customize how sessions persist in the browser and where users land after an OAuth round trip. + +```ts +createAppwriteHandlers({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: "/api/appwrite", + cookieName: "my-app-session", + cookieOptions: { + sameSite: "strict", + domain: ".example.com", + }, + redirects: { + success: "/dashboard", + failure: "/login?error=oauth", + }, +}); +``` + +| Option | Default | Description | +| --- | --- | --- | +| `cookieName` | `appwrite-session-` | Name of the HTTP-only session cookie. | +| `cookieOptions.secure` | `true` | Set the `Secure` flag on the cookie. Modern browsers accept this on `localhost` over HTTP. | +| `cookieOptions.sameSite` | `"lax"` | SameSite policy. | +| `cookieOptions.httpOnly` | `true` | HttpOnly flag. | +| `cookieOptions.path` | `"/"` | Cookie path. | +| `cookieOptions.domain` | unset | Restrict cookie to a domain. | +| `redirects.success` | `"/"` | URL to redirect to after a successful OAuth login. | +| `redirects.failure` | `"/"` | URL to redirect to after a failed OAuth attempt. | + +# Required scopes {% #scopes %} + +Your server API key needs three scopes for the SSR handler to function: + +- `users.write` (sign-up creates a user) +- `users.read` (sign-up confirms the created user) +- `sessions.write` (sign-in, sign-out, and OAuth callbacks create or delete sessions) + +# Next steps {% #next-steps %} + +- [Start with React](/docs/quick-starts/react) +- [Start with Next.js](/docs/quick-starts/nextjs) +- [Start with TanStack Start](/docs/quick-starts/tanstack-start) +- [Account API reference](/docs/references/cloud/client-web/account) diff --git a/src/routes/docs/quick-starts/nextjs/+page.markdoc b/src/routes/docs/quick-starts/nextjs/+page.markdoc index 3487e84f12f..cad7ea61b8c 100644 --- a/src/routes/docs/quick-starts/nextjs/+page.markdoc +++ b/src/routes/docs/quick-starts/nextjs/+page.markdoc @@ -1,12 +1,14 @@ --- layout: article title: Start with Next.js -description: Learn how to use Appwrite to add authentication, user management, file storage, and more to your Next.js apps. +description: Build Next.js apps with the Appwrite React library. Add server-rendered authentication, sign-in, sign-up, and user state without writing the SSR plumbing yourself. difficulty: beginner -readtime: 3 +readtime: 7 back: /docs/quick-starts --- -Learn how to setup your first Next.js project powered by Appwrite. + +Learn how to set up your first Next.js project with the [Appwrite React library](/docs/products/auth/react). The library ships SSR auth handlers, server helpers, and the same React hooks you use on the client. + {% section #step-1 step=1 title="Create project" %} Head to the [Appwrite Console](https://cloud.appwrite.io/console). @@ -33,99 +35,178 @@ Then, under **Add a platform**, add a **Web app**. The **Hostname** should be `l You can skip optional steps. {% /section %} -{% section #step-2 step=2 title="Create Next.js project" %} -Create a Next.js project by running the following command: + +{% section #step-2 step=2 title="Create an API key" %} + +In your project, go to **Overview** > **Integrations** > **API keys** and create a new key with the scopes `users.read`, `users.write`, and `sessions.write`. Copy the key secret. The SSR handler uses this to create sessions on behalf of users; never expose it to the browser. + +{% /section %} + +{% section #step-3 step=3 title="Create Next.js project" %} + +Create a Next.js project with TypeScript and the App Router. ```sh -npx create-next-app@latest && cd my-app +npx create-next-app@latest my-app --ts --app && cd my-app ``` -When prompted, configure your project with these recommended settings: -- **Would you like to use TypeScript?** → No -- **Would you like to use ESLint?** → Yes -- **Would you like to use Tailwind CSS?** → No (unless you plan to use it) -- **Would you like to use `src/` directory?** → Yes/No (either works for this tutorial) -- **Would you like to use App Router?** → Yes -- **Would you like to customize the default import alias?** → No +Accept the defaults for the remaining prompts. -These settings will create a minimal Next.js setup that's perfect for getting started with Appwrite. {% /section %} -{% section #step-3 step=3 title="Install Appwrite SDK" %} -Install the JavaScript Appwrite SDK. +{% section #step-4 step=4 title="Install the React library" %} + +Install the React library along with the Appwrite Web SDK, Appwrite Node SDK, and `@tanstack/react-query` packages. ```sh -npm install appwrite +npm install @appwrite.io/react appwrite node-appwrite @tanstack/react-query ``` + {% /section %} -{% section #step-4 step=4 title="Define Appwrite service" %} -Find your project's ID in the **Settings** page. -{% only_dark %} -![Project settings screen](/images/docs/quick-starts/dark/project-id.avif) -{% /only_dark %} -{% only_light %} -![Project settings screen](/images/docs/quick-starts/project-id.avif) -{% /only_light %} +{% section #step-5 step=5 title="Configure environment variables" %} + +Create a `.env.local` file at the project root. Replace ``, ``, and `` with your own values. + +```sh +NEXT_PUBLIC_APPWRITE_ENDPOINT=https://.cloud.appwrite.io/v1 +NEXT_PUBLIC_APPWRITE_PROJECT_ID= +APPWRITE_API_KEY= +``` + +`NEXT_PUBLIC_*` values are shipped to the browser. `APPWRITE_API_KEY` stays server-only. + +{% /section %} + +{% section #step-6 step=6 title="Mount the auth handler route" %} + +Create `app/api/appwrite/[...appwrite]/route.ts`. The handler exposes the `sign-in`, `sign-up`, `sign-out`, and `oauth/callback` endpoints that the React hooks POST to in SSR mode. + +```ts +import { createAppwriteHandlers } from "@appwrite.io/react/handlers/next"; + +export const { GET, POST } = createAppwriteHandlers({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: "/api/appwrite", +}); +``` + +{% /section %} + +{% section #step-7 step=7 title="Wrap your app with AppwriteProvider" %} + +Create `app/providers.tsx`. The provider runs in client components and accepts the SSR session secret as a prop so the underlying Web SDK can hydrate authenticated. + +```tsx +"use client"; + +import { AppwriteProvider } from "@appwrite.io/react"; + +export function Providers({ + session, + children, +}: { + session?: string | null; + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} +``` -Create a new file `app/appwrite.js` and add the following code to it, replace `` with your project ID. +Replace `app/layout.tsx` with the following. It reads the session cookie on the server and passes it into the provider. -```client-web -import { Client, Account } from 'appwrite'; +```tsx +import { createNextServerHelpers } from "@appwrite.io/react/server/next"; +import { Providers } from "./providers"; -export const client = new Client(); +const appwrite = { + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, +}; -client - .setEndpoint('https://.cloud.appwrite.io/v1') - .setProject(''); // Replace with your project ID +export default async function RootLayout({ + children, +}: Readonly<{ children: React.ReactNode }>) { + const helpers = createNextServerHelpers(appwrite); + const session = await helpers.readSessionCookie(); -export const account = new Account(client); -export { ID } from 'appwrite'; + return ( + + + {children} + + + ); +} +``` + +{% /section %} + +{% section #step-8 step=8 title="Read the user on the server" %} + +Replace `app/page.tsx`. `getLoggedInUser()` calls the Appwrite API server-side with the session cookie, so the user is rendered with the first byte. + +```tsx +import { createNextServerHelpers } from "@appwrite.io/react/server/next"; +import { AuthPanel } from "./auth-panel"; + +const appwrite = { + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, +}; + +export default async function Page() { + const helpers = createNextServerHelpers(appwrite); + const user = await helpers.getLoggedInUser(); + + return ( +
+

Appwrite React library on Next.js

+

SSR user: {user?.email ?? "signed out"}

+ +
+ ); +} ``` + {% /section %} -{% section #step-5 step=5 title="Create a login page" %} -Create or update `app/page.js` file and add the following code to it. -```js +{% section #step-9 step=9 title="Add the client auth panel" %} + +Create `app/auth-panel.tsx`. The hooks POST to the handler route, the server sets a cookie, and `router.refresh()` re-runs the server component so the SSR user updates. + +```tsx "use client"; + import { useState } from "react"; -import { account, ID } from "./appwrite"; +import { useAuth } from "@appwrite.io/react"; +import { useRouter } from "next/navigation"; -const LoginPage = () => { - const [loggedInUser, setLoggedInUser] = useState(null); +export function AuthPanel() { + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const router = useRouter(); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [name, setName] = useState(""); - const login = async (email, password) => { - const session = await account.createEmailPasswordSession({ - email, - password - }); - setLoggedInUser(await account.get()); - }; - - const register = async () => { - await account.create({ - userId: ID.unique(), - email, - password, - name - }); - login(email, password); - }; - - const logout = async () => { - await account.deleteSession({ sessionId: 'current' }); - setLoggedInUser(null); - }; - - if (loggedInUser) { + if (isLoading) return

Loading...

; + + if (user) { return (
-

Logged in as {loggedInUser.name}

-
); @@ -133,43 +214,57 @@ const LoginPage = () => { return (
-

Not logged in

-
- setEmail(e.target.value)} - /> - setPassword(e.target.value)} - /> - setName(e.target.value)} - /> - - -
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

}
); -}; - -export default LoginPage; +} ``` + {% /section %} -{% section #step-6 step=6 title="All set" %} -Run your project with `npm run dev` and open [Localhost on Port 3000](http://localhost:3000) in your browser. +{% section #step-10 step=10 title="Run your app" %} + +```sh +npm run dev +``` + +Open [localhost on port 3000](http://localhost:3000). Sign up, sign out, and sign back in to verify the cookie-based SSR flow. -Don't forget to add some CSS to suit your style. {% /section %} + +# Next steps {% #next-steps %} + +For server-side admin operations, per-request session clients, OAuth callbacks, and the full hook reference, see the [React library docs](/docs/products/auth/react). diff --git a/src/routes/docs/quick-starts/react/+page.markdoc b/src/routes/docs/quick-starts/react/+page.markdoc index f416f6981a5..da8e8fd8eec 100644 --- a/src/routes/docs/quick-starts/react/+page.markdoc +++ b/src/routes/docs/quick-starts/react/+page.markdoc @@ -1,13 +1,14 @@ --- layout: article title: Start with React -description: Build React apps with Appwrite and learn how to use our powerful backend to add authentication, user management, file storage, and more. +description: Build React apps with the Appwrite React library and add authentication, sign-in, sign-up, and user state in a few lines. difficulty: beginner -readtime: 3 +readtime: 5 back: /docs/quick-starts --- -Learn how to setup your first React project powered by Appwrite. +Learn how to set up your first React project with the [Appwrite React library](/docs/products/auth/react). + {% section #step-1 step=1 title="Create project" %} Head to the [Appwrite Console](https://cloud.appwrite.io/console). @@ -34,22 +35,26 @@ Then, under **Add a platform**, add a **Web app**. The **Hostname** should be `l You can skip optional steps. {% /section %} + {% section #step-2 step=2 title="Create React project" %} Create a Vite project. ```sh -npm create vite@latest my-app -- --template react && cd my-app +npm create vite@latest my-app -- --template react-ts && cd my-app +npm install ``` {% /section %} -{% section #step-3 step=3 title="Install Appwrite" %} -Install the JavaScript Appwrite SDK. +{% section #step-3 step=3 title="Install the React library" %} + +Install the Appwrite React library along with the `appwrite` Web SDK and `@tanstack/react-query` peer dependency. ```sh -npm install appwrite +npm install @appwrite.io/react appwrite @tanstack/react-query ``` {% /section %} -{% section #step-4 step=4 title="Import Appwrite" %} + +{% section #step-4 step=4 title="Configure environment variables" %} Find your project's ID in the **Settings** page. {% only_dark %} @@ -58,92 +63,109 @@ Find your project's ID in the **Settings** page. {% only_light %} ![Project settings screen](/images/docs/quick-starts/project-id.avif) {% /only_light %} -Create a new file `src/lib/appwrite.js` and add the following code to it, replace `` with your project ID. - -```client-web -import { Client, Account} from 'appwrite'; -export const client = new Client(); +Create a `.env` file at the project root and add your endpoint and project ID. Replace `` and `` with your own values. -client - .setEndpoint('https://.cloud.appwrite.io/v1') - .setProject(''); // Replace with your project ID +```sh +VITE_APPWRITE_ENDPOINT=https://.cloud.appwrite.io/v1 +VITE_APPWRITE_PROJECT_ID= +``` +{% /section %} -export const account = new Account(client); -export { ID } from 'appwrite'; +{% section #step-5 step=5 title="Wrap your app with AppwriteProvider" %} + +Replace the contents of `src/main.tsx` with the following. + +```tsx +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import { AppwriteProvider } from "@appwrite.io/react"; +import App from "./App"; +import "./index.css"; + +createRoot(document.getElementById("root")!).render( + + + + + , +); ``` + +`AppwriteProvider` sets up the Appwrite Web SDK client and a per-instance TanStack Query cache so all hooks share the same auth state. + {% /section %} -{% section #step-5 step=5 title="Create a login page" %} -Add the following code to `src/App.jsx`. - -```js -import React, { useState } from 'react'; -import { account, ID } from './lib/appwrite'; - -const App = () => { - const [loggedInUser, setLoggedInUser] = useState(null); - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [name, setName] = useState(''); - - async function login(email, password) { - await account.createEmailPasswordSession({ - email, - password - }); - setLoggedInUser(await account.get()); + +{% section #step-6 step=6 title="Add sign-up, sign-in, and sign-out" %} + +Replace the contents of `src/App.tsx` with the following. + +```tsx +import { useState } from "react"; +import { useAuth } from "@appwrite.io/react"; + +export default function App() { + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [name, setName] = useState(""); + + if (isLoading) return

Loading...

; + + if (user) { + return ( +
+

Welcome, {user.name || user.email}

+ +
+ ); } return ( -
-

- {loggedInUser ? `Logged in as ${loggedInUser.name}` : 'Not logged in'} -

- -
- setEmail(e.target.value)} /> - setPassword(e.target.value)} /> - setName(e.target.value)} /> - - - - - - -
-
+
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

} +
); -}; +} +``` + +`useAuth` returns the current user, loading state, and the `signIn`, `signUp`, and `signOut` mutations. The user state is cached by TanStack Query and stays in sync across components automatically. -export default App; +{% /section %} + +{% section #step-7 step=7 title="Run your app" %} +Run your project. + +```sh +npm run dev ``` + +Open [localhost on port 5173](http://localhost:5173) in your browser. Sign up, sign out, and sign back in to verify the flow. {% /section %} -{% section #step-6 step=6 title="All set" %} -Run your project with `npm run dev -- --open --port 3000` and open [Localhost on Port 3000](http://localhost:3000) in your browser. -{% /section %} \ No newline at end of file +# Next steps {% #next-steps %} + +For Next.js or TanStack Start integration, server-side rendering, and the full hook reference, see the [React library docs](/docs/products/auth/react). diff --git a/src/routes/docs/quick-starts/tanstack-start/+page.markdoc b/src/routes/docs/quick-starts/tanstack-start/+page.markdoc index 780ec427580..b658191bdf6 100644 --- a/src/routes/docs/quick-starts/tanstack-start/+page.markdoc +++ b/src/routes/docs/quick-starts/tanstack-start/+page.markdoc @@ -1,12 +1,14 @@ --- layout: article title: Start with TanStack Start -description: Learn how to use Appwrite to add authentication, user management, file storage, and more to your TanStack Start apps. +description: Build TanStack Start apps with the Appwrite React library. Add server-rendered authentication via file-route handlers and server functions. difficulty: beginner -readtime: 3 +readtime: 7 back: /docs/quick-starts --- -Learn how to setup your first TanStack Start project powered by Appwrite. + +Learn how to set up your first TanStack Start project with the [Appwrite React library](/docs/products/auth/react). The library exposes a TanStack file-route handler, server helpers, and the same React hooks you use on the client. + {% section #step-1 step=1 title="Create project" %} Head to the [Appwrite Console](https://cloud.appwrite.io/console). @@ -33,133 +35,189 @@ Then, under **Add a platform**, add a **Web app**. The **Hostname** should be `l You can skip optional steps. {% /section %} -{% section #step-2 step=2 title="Create TanStack Start project" %} + +{% section #step-2 step=2 title="Create an API key" %} + +In your project, go to **Overview** > **Integrations** > **API keys** and create a new key with the scopes `users.read`, `users.write`, and `sessions.write`. Copy the key secret. The SSR handler uses this to create sessions on behalf of users; never expose it to the browser. + +{% /section %} + +{% section #step-3 step=3 title="Create TanStack Start project" %} + Create a TanStack Start project. ```sh -npm create @tanstack/start@latest my-app && cd my-app +npx @tanstack/cli create my-app --framework react && cd my-app ``` + {% /section %} -{% section #step-3 step=3 title="Install Appwrite" %} -Install the JavaScript Appwrite SDK. +{% section #step-4 step=4 title="Install the React library" %} + +Install the React library along with the Appwrite Web SDK, Appwrite Node SDK, and `@tanstack/react-query` packages. ```sh -npm install appwrite +npm install @appwrite.io/react appwrite node-appwrite @tanstack/react-query ``` + {% /section %} -{% section #step-4 step=4 title="Import Appwrite" %} -Find your project's ID in the **Settings** page. -{% only_dark %} -![Project settings screen](/images/docs/quick-starts/dark/project-id.avif) -{% /only_dark %} -{% only_light %} -![Project settings screen](/images/docs/quick-starts/project-id.avif) -{% /only_light %} -Create a new file `src/utils/appwrite.ts` and add the following code to it, replace `` with your project ID. +{% section #step-5 step=5 title="Configure environment variables" %} + +Create a `.env` file at the project root. Replace ``, ``, and `` with your own values. + +```sh +VITE_APPWRITE_ENDPOINT=https://.cloud.appwrite.io/v1 +VITE_APPWRITE_PROJECT_ID= +APPWRITE_API_KEY= +``` + +`VITE_*` values are shipped to the browser. `APPWRITE_API_KEY` stays server-only. + +{% /section %} -```client-web -import { Client, Account, ID, Models } from 'appwrite'; +{% section #step-6 step=6 title="Mount the auth handler route" %} -export const client = new Client(); +Create `src/routes/api/appwrite/$.ts`. The TanStack file route exposes the library's `sign-in`, `sign-up`, `sign-out`, and `oauth/callback` endpoints under `/api/appwrite/*`. -client - .setEndpoint('https://.cloud.appwrite.io/v1') - .setProject(''); // Replace with your project ID +```ts +import { createFileRoute } from "@tanstack/react-router"; +import { createAppwriteHandlers } from "@appwrite.io/react/handlers/tanstack"; -export const account = new Account(client); -export { ID }; -export type { Models }; +export const Route = createFileRoute("/api/appwrite/$")({ + server: { + handlers: createAppwriteHandlers({ + endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT, + projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: "/api/appwrite", + }), + }, +}); ``` + {% /section %} -{% section #step-5 step=5 title="Create a login page" %} -Create or update `src/routes/index.tsx` with the following code. + +{% section #step-7 step=7 title="Read auth state in a server function" %} + +Replace `src/routes/index.tsx` with the following. A `createServerFn` loader reads the session cookie server-side; the page receives the result via `Route.useLoaderData()` and passes it into `AppwriteProvider`. ```tsx -import { useState } from 'react'; -import { createFileRoute } from '@tanstack/react-router'; -import { account, ID, type Models } from '../utils/appwrite'; +import { useState } from "react"; +import { createFileRoute, useRouter } from "@tanstack/react-router"; +import { createServerFn } from "@tanstack/react-start"; +import { AppwriteProvider, useAuth } from "@appwrite.io/react"; +import { createTanStackServerHelpers } from "@appwrite.io/react/server/tanstack"; + +const getAuthSnapshot = createServerFn({ method: "GET" }).handler(async () => { + const helpers = createTanStackServerHelpers({ + endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT, + projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID, + }); + return { + session: helpers.readSessionCookie() ?? null, + user: await helpers.getLoggedInUser(), + }; +}); -export const Route = createFileRoute('/')({ - component: Index, +export const Route = createFileRoute("/")({ + loader: () => getAuthSnapshot(), + component: Page, }); -function Index() { - const [loggedInUser, setLoggedInUser] = useState | null>(null); - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [name, setName] = useState(''); +function Page() { + const { session, user } = Route.useLoaderData(); + + return ( + +
+

Appwrite React library on TanStack Start

+

SSR user: {user?.email ?? "signed out"}

+ +
+
+ ); +} - async function login(email: string, password: string) { - await account.createEmailPasswordSession({ - email, - password, - }); - setLoggedInUser(await account.get()); - } +function AuthPanel() { + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const router = useRouter(); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [name, setName] = useState(""); - async function register() { - await account.create({ - userId: ID.unique(), - email, - password, - name, - }); - await login(email, password); - } - - async function logout() { - await account.deleteSession({ sessionId: 'current' }); - setLoggedInUser(null); - } - - if (loggedInUser) { - return ( -
-

Logged in as {loggedInUser.name}

- -
- ); - } + if (isLoading) return

Loading...

; + if (user) { return ( -
-

Not logged in

-
- setEmail(e.target.value)} - /> - setPassword(e.target.value)} - /> - setName(e.target.value)} - /> - - -
-
+
+

Welcome, {user.name || user.email}

+ +
); + } + + return ( +
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

} +
+ ); } ``` + +After every auth mutation, `router.invalidate()` re-runs the loader so the SSR user reflects the new session cookie. + {% /section %} -{% section #step-6 step=6 title="All set" %} -Run your project with `npm run dev` and open [localhost on port 3000](http://localhost:3000) in your browser. +{% section #step-8 step=8 title="Run your app" %} + +```sh +npm run dev +``` + +Open [localhost on port 3000](http://localhost:3000). Sign up, sign out, and sign back in to verify the cookie-based SSR flow. + {% /section %} + +# Next steps {% #next-steps %} + +For server-side admin operations, per-request session clients, OAuth callbacks, and the full hook reference, see the [React library docs](/docs/products/auth/react). diff --git a/src/routes/docs/sdks/+page.markdoc b/src/routes/docs/sdks/+page.markdoc index 5ad3c160477..c8239b4102b 100644 --- a/src/routes/docs/sdks/+page.markdoc +++ b/src/routes/docs/sdks/+page.markdoc @@ -32,6 +32,12 @@ Client libraries for integrating with Appwrite to build client-based application --- * {% only_dark %}{% icon_image src="/images/platforms/dark/react.svg" alt="React logo" size="m" /%}{% /only_dark %} {% only_light %}{% icon_image src="/images/platforms/light/react.svg" alt="React logo" size="m" /%}{% /only_light %} +* React library `0.1.0` +* [appwrite/sdk-for-react](https://github.com/appwrite/sdk-for-react) +* +--- +* {% only_dark %}{% icon_image src="/images/platforms/dark/react.svg" alt="React logo" size="m" /%}{% /only_dark %} +{% only_light %}{% icon_image src="/images/platforms/light/react.svg" alt="React logo" size="m" /%}{% /only_light %} * React Native SDK `0.25.0` * [appwrite/sdk-for-react-native](https://github.com/appwrite/sdk-for-react-native) * `beta` From ab6233b0a6e4162c6210563d770ca3b31d291e7c Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Mon, 25 May 2026 20:52:07 +0530 Subject: [PATCH 02/61] Update quickstart AI prompts for React library Rewrites the AI quickstart prompts under react/, nextjs/, and tanstack-start/ to use @appwrite.io/react instead of the raw Appwrite Web SDK setup, mirroring the rewritten +page.markdoc files. --- src/routes/docs/quick-starts/nextjs/prompt.md | 218 ++++++++++++++---- src/routes/docs/quick-starts/react/prompt.md | 128 +++++++--- .../quick-starts/tanstack-start/prompt.md | 211 ++++++++++------- 3 files changed, 386 insertions(+), 171 deletions(-) diff --git a/src/routes/docs/quick-starts/nextjs/prompt.md b/src/routes/docs/quick-starts/nextjs/prompt.md index 2e159d12260..c0ce195f3c8 100644 --- a/src/routes/docs/quick-starts/nextjs/prompt.md +++ b/src/routes/docs/quick-starts/nextjs/prompt.md @@ -1,80 +1,210 @@ ## Add Appwrite Auth to a New Next.js App -Add Appwrite auth to a new Next.js app (**App Router**), with a working login/register/logout page. +Add Appwrite auth to a new Next.js app (**App Router**) using the official Appwrite React library, with a working sign-up, sign-in, and sign-out flow backed by SSR session cookies. - Do exactly these steps in order. Confirm each step succeeds before continuing. If any command fails, show the error and fix it automatically. - Respect the user's package manager at all times. Do not use NPM if the user uses something else. -## Step 1: Create or Use Existing Next.js App +## Step 1: Create or use existing Next.js app - First, check if the current working directory contains files that appear unrelated to a development workspace (e.g., personal files, downloads, random documents, media files). If so, ask the user: "This directory contains files that don't look like a development project. Would you like to proceed here anyway, or create a subdirectory with a specific folder name?" - If the directory is empty OR contains an existing project (`package.json`, source code, config files, etc.), proceed with integration without asking. - Create the project in the current working directory (`.`) - do NOT use `cd` to switch directories. - If you already have a Next.js project open, stay in it and integrate Appwrite into it (**App Router** required). -- Otherwise, run: `npx create-next-app@latest . --eslint` -- When prompted: **TypeScript** = No, **ESLint** = Yes, **Tailwind** = No, **src dir** = your choice, **App Router** = Yes, **Import alias** = No. +- Otherwise, run: `npx create-next-app@latest . --ts --app` +- Accept the defaults for the remaining prompts. -## Step 2: Install Appwrite SDK +## Step 2: Install the Appwrite React library -- Run: `npm install appwrite` +- Run: `npm install @appwrite.io/react appwrite node-appwrite @tanstack/react-query` -## Step 3: Create Appwrite Client Module +## Step 3: Configure environment variables _Ask the user for details; never assume._ - Ask the user for: - **Appwrite Cloud Region** (e.g. `fra`, `nyc`) - **Project ID** (from Console -> Settings) -- If the user doesn't know, guide them to the **Appwrite Console** to copy these. Do not attempt to infer or access their project. -- Hardcode the endpoint and project ID in the file `app/appwrite.js` (or `app/appwrite.ts` if TS) if provided, else leave a placeholder and ask the user to provide them. -- Create file `app/appwrite.js` (or `app/appwrite.ts` if TS) with key snippet: - -```js -import { Client, Account } from 'appwrite'; -const endpoint = ''; -const projectId = ''; -if (!endpoint || !projectId) throw new Error('Missing Appwrite endpoint and project ID'); -export const client = new Client().setEndpoint(endpoint).setProject(projectId); -export const account = new Account(client); -export { ID } from 'appwrite'; + - **API key** with scopes `users.read`, `users.write`, `sessions.write` (Console -> Overview -> Integrations -> API keys) +- Create a `.env.local` file at the project root: + +```sh +NEXT_PUBLIC_APPWRITE_ENDPOINT=https://.cloud.appwrite.io/v1 +NEXT_PUBLIC_APPWRITE_PROJECT_ID= +APPWRITE_API_KEY= +``` + +- The `APPWRITE_API_KEY` is server-only. Never expose it to the browser. + +## Step 4: Mount the auth handler route + +- Create `app/api/appwrite/[...appwrite]/route.ts` so the library's sign-in, sign-up, sign-out, and OAuth callback endpoints are reachable: + +```ts +import { createAppwriteHandlers } from "@appwrite.io/react/handlers/next"; + +export const { GET, POST } = createAppwriteHandlers({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: "/api/appwrite", +}); +``` + +## Step 5: Wrap the app with AppwriteProvider + +- Create `app/providers.tsx`: + +```tsx +"use client"; + +import { AppwriteProvider } from "@appwrite.io/react"; + +export function Providers({ + session, + children, +}: { + session?: string | null; + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} +``` + +- Replace `app/layout.tsx` to read the session cookie server-side and pass it into the provider: + +```tsx +import { createNextServerHelpers } from "@appwrite.io/react/server/next"; +import { Providers } from "./providers"; + +const appwrite = { + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, +}; + +export default async function RootLayout({ + children, +}: Readonly<{ children: React.ReactNode }>) { + const helpers = createNextServerHelpers(appwrite); + const session = await helpers.readSessionCookie(); + + return ( + + + {children} + + + ); +} ``` -## Step 4: Build the Login Page (Client Component) +## Step 6: Build the auth page + +- If this is a fresh project you just created, replace `app/page.tsx` to read the user server-side and render the auth panel. If you are working in an existing project, create a new route (e.g. `app/auth/page.tsx`) instead of overriding the default route. + +```tsx +import { createNextServerHelpers } from "@appwrite.io/react/server/next"; +import { AuthPanel } from "./auth-panel"; + +const appwrite = { + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, +}; + +export default async function Page() { + const helpers = createNextServerHelpers(appwrite); + const user = await helpers.getLoggedInUser(); -- If this is a fresh project you just created above, you may replace `app/page.js` with this component using `"use client"`. -- If you are working in an existing project, create a new route `app/auth/page.js` (or `.tsx`) instead of overriding the default route. -- It must render: - - Email/password inputs - - Name input for registration - - Buttons: **Login**, **Register**, **Logout** - - Shows "Logged in as \" when a session exists -- Implement functions: - - `login(email, password)`: `account.createEmailPasswordSession({ email, password })` then set user via `account.get()` - - `register()`: `account.create({ userId: ID.unique(), email, password, name })` then call `login` - - `logout()`: `account.deleteSession({ sessionId: 'current' })` then clear user state + return ( +
+

SSR user: {user?.email ?? "signed out"}

+ +
+ ); +} +``` + +- Create `app/auth-panel.tsx` for the client-side hook usage: + +```tsx +"use client"; + +import { useState } from "react"; +import { useAuth } from "@appwrite.io/react"; +import { useRouter } from "next/navigation"; + +export function AuthPanel() { + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const router = useRouter(); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [name, setName] = useState(""); + + if (isLoading) return

Loading...

; + + if (user) { + return ( + + ); + } + + return ( +
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

} +
+ ); +} +``` -## Step 5: Verify Environment +## Step 7: Verify environment _Ask the user to confirm._ -- Confirm with the user that the endpoint and project ID are hardcoded in the file `app/appwrite.js` (or `app/appwrite.ts` if TS). +- Confirm `.env.local` has the endpoint, project ID, and API key set. - Ensure the **Web** app platform exists in **Appwrite Console** with **Hostname** = `localhost`. If missing, guide the user to add it. -## Step 6: Run and Test +## Step 8: Run and test - Run: `npm run dev` - Open: `http://localhost:3000` - Test flows: - - Register a new user and auto login works - - Logout then login again -- Surface any Appwrite errors (invalid project, endpoint, CORS/hostname) and fix by guiding updates to `appwrite.js` and **Console** settings. - -## Step 7: Optional Hardening - -- If the user wants TypeScript, create `app/appwrite.ts` and `app/page.tsx` with proper types. -- Add minimal styling if requested; functionality first. + - Sign up a new user, confirm the SSR-rendered user reflects the change after `router.refresh()` + - Sign out, then sign in again +- Surface any Appwrite errors (invalid project, endpoint, CORS/hostname, missing key scopes) and fix by guiding updates to `.env.local` and Console settings. ## Deliverables -- A running Next.js app with working Appwrite auth (register/login/logout) -- Files created/updated: `package.json` (deps), `app/appwrite.js`, `app/page.js` +- A running Next.js app with working Appwrite auth using `@appwrite.io/react` +- Files created/updated: `package.json` (deps), `.env.local`, `app/api/appwrite/[...appwrite]/route.ts`, `app/providers.tsx`, `app/layout.tsx`, `app/page.tsx`, `app/auth-panel.tsx` diff --git a/src/routes/docs/quick-starts/react/prompt.md b/src/routes/docs/quick-starts/react/prompt.md index c2f180be592..ad75ced5b44 100644 --- a/src/routes/docs/quick-starts/react/prompt.md +++ b/src/routes/docs/quick-starts/react/prompt.md @@ -1,6 +1,6 @@ ## Add Appwrite Auth to a New React (Vite) App -Goal: Add Appwrite auth to a new React (Vite) app with a working login/register/logout page. +Goal: Add Appwrite auth to a new React (Vite) app using the official Appwrite React library, with a working sign-up, sign-in, and sign-out flow. Do exactly these steps in order. Confirm each step succeeds before continuing. If any command fails, show the error and fix it automatically. @@ -11,60 +11,112 @@ Respect user's package manager at all time. Don't use NPM if the user uses somet - First, check if the current working directory contains files that appear unrelated to a development workspace (e.g., personal files, downloads, random documents, media files). - If unrelated files are detected, ask the user: 'The current directory appears to contain personal or non-project files. Would you like to: (1) proceed here anyway, or (2) create the project in a subdirectory with a specific folder name?' and proceed based on their choice. - If the directory is empty OR contains an existing project (`package.json`, source files, config files, etc.), proceed without asking - integrate Appwrite into whatever is there. -- For a new project, run: `npm create vite@latest . -- --template react` +- For a new project, run: `npm create vite@latest . -- --template react-ts` - Create the project in the current directory (`.`). Do NOT use `cd` to switch directories. -## Step 2: Install Appwrite SDK +## Step 2: Install the Appwrite React library -- Run: `npm install appwrite` +- Run: `npm install @appwrite.io/react appwrite @tanstack/react-query` -## Step 3: Create Appwrite Client Module (Ask User for Details; Never Assume) +## Step 3: Configure environment variables (Ask User for Details; Never Assume) - Ask the user for: - Appwrite Cloud Region (e.g. `fra`, `nyc`) - **Project ID** (from Console -> Settings) -- Hardcode the endpoint and project ID in the file: `src/lib/appwrite.js` (or `.ts`) if provided, else leave placeholder and ask the user to provide them. -- Create file: `src/lib/appwrite.js` (or `.ts`) with key snippet: - -```js -import { Client, Account, ID } from 'appwrite'; -const endpoint = 'https://.cloud.appwrite.io/v1'; -const projectId = ''; -if (!endpoint || !projectId) throw new Error('Missing Appwrite endpoint and project ID'); -const client = new Client().setEndpoint(endpoint).setProject(projectId); -export const account = new Account(client); -export { ID }; +- Create a `.env` file at the project root with the values provided. If either is missing, leave a placeholder and ask the user to fill it in: + +```sh +VITE_APPWRITE_ENDPOINT=https://.cloud.appwrite.io/v1 +VITE_APPWRITE_PROJECT_ID= ``` -## Step 4: Build the Login Page +## Step 4: Mount AppwriteProvider + +- Replace `src/main.tsx` (or `.jsx`) so the entire app is wrapped with `AppwriteProvider`: + +```tsx +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import { AppwriteProvider } from "@appwrite.io/react"; +import App from "./App"; +import "./index.css"; + +createRoot(document.getElementById("root")!).render( + + + + + , +); +``` -- If this is a fresh project, you may replace `src/App.jsx` (or `.tsx`) with a component that renders the auth UI. -- If you are working in an existing project, add a new route/page instead of overriding the default route. If routing is not set up, install `react-router-dom` and add a `/auth` route that renders this component. -- The component should render: - - Email/password inputs - - Name input for registration - - Buttons: **Login**, **Register**, **Logout** - - Shows "Logged in as \" when a session exists -- Implement functions: - - `login(email, password)`: `account.createEmailPasswordSession({ email, password })` then set user via `account.get()` - - `register()`: `account.create({ userId: ID.unique(), email, password, name })` then call `login` - - `logout()`: `account.deleteSession({ sessionId: 'current' })` then clear user state +## Step 5: Build the auth page + +- If this is a fresh project, you may replace `src/App.tsx` (or `.jsx`) with a component that renders the auth UI. +- If you are working in an existing project, add a new route/page instead of overriding the default route. If routing is not set up, install `react-router-dom` and add an `/auth` route that renders this component. +- The component must render: + - Email, password, and name inputs + - Buttons: **Sign up**, **Sign in**, **Sign out** + - Shows "Welcome, \" when a session exists +- Use the `useAuth` hook from `@appwrite.io/react`: + +```tsx +import { useState } from "react"; +import { useAuth } from "@appwrite.io/react"; + +export default function App() { + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [name, setName] = useState(""); + + if (isLoading) return

Loading...

; + + if (user) { + return ( +
+

Welcome, {user.name || user.email}

+ +
+ ); + } + + return ( +
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

} +
+ ); +} +``` -## Step 5: Verify Environment (Ask User to Confirm) +## Step 6: Verify environment (Ask User to Confirm) -- Confirm endpoint and project ID are set in `src/lib/appwrite.js`. +- Confirm the `.env` file contains the correct endpoint and project ID. - Ensure the Web app platform exists in Appwrite Console with **Hostname** = `localhost`. If missing, guide the user to add it. -## Step 6: Run and Test +## Step 7: Run and test -- Run: `npm run dev -- --open --port 3000` -- Open: `http://localhost:3000` +- Run: `npm run dev` +- Open: `http://localhost:5173` - Test flows: - - Register a new user and auto login works - - Logout then login again -- Surface any Appwrite errors (invalid project, endpoint, CORS/hostname) and fix by guiding updates to `appwrite.js` and Console settings. + - Sign up a new user and confirm the page shows the welcome state + - Sign out, then sign in again +- Surface any Appwrite errors (invalid project, endpoint, CORS/hostname) and fix by guiding updates to `.env` and Console settings. ## Deliverables -- A running React app with working Appwrite auth (register/login/logout) -- Files created/updated: `package.json` (deps), `src/lib/appwrite.js`, `src/App.jsx` +- A running React app with working Appwrite auth using `@appwrite.io/react` +- Files created/updated: `package.json` (deps), `.env`, `src/main.tsx`, `src/App.tsx` diff --git a/src/routes/docs/quick-starts/tanstack-start/prompt.md b/src/routes/docs/quick-starts/tanstack-start/prompt.md index 1292b29b194..d8a8885e373 100644 --- a/src/routes/docs/quick-starts/tanstack-start/prompt.md +++ b/src/routes/docs/quick-starts/tanstack-start/prompt.md @@ -1,4 +1,6 @@ -## Add Appwrite auth to a TanStack Start app with a working login/register/logout page +## Add Appwrite Auth to a TanStack Start app + +Add Appwrite auth to a new TanStack Start app using the official Appwrite React library, with a working sign-up, sign-in, and sign-out flow backed by SSR session cookies. Do exactly these steps in order. Confirm each step succeeds before continuing. If any command fails, show the error and fix it automatically. @@ -9,126 +11,157 @@ Respect the user's package manager at all times. Don't use NPM if the user uses - First, check what files exist in the current working directory. - If the directory contains files that appear unrelated to a development workspace (e.g., personal documents, downloads, photos, random files that don't belong in a code project), ask the user: "The current directory contains files that don't appear to be part of a development project. Would you like to proceed here anyway, or create a subdirectory with a specific folder name?" - If the directory is empty OR contains an existing project (`package.json`, config files, `src` folder, etc.), proceed with integration without asking - just work with what's there. -- To scaffold a new TanStack Start project, run: `npm create @tanstack/start@latest .` (use `.` to create in the current directory - do NOT use `cd` to switch directories) +- To scaffold a new TanStack Start project, run: `npx @tanstack/cli create . --framework react` (use `.` to create in the current directory - do NOT use `cd` to switch directories) + +## Step 2: Install the Appwrite React library -## Step 2: Install Appwrite SDK +- Run: `npm install @appwrite.io/react appwrite node-appwrite @tanstack/react-query` -- Run: `npm install appwrite` +## Step 3: Configure environment variables -## Step 3: Create Appwrite client module (ask user for details; never assume) +_Ask the user for details; never assume._ - Ask the user for: - **Appwrite Cloud Region** (e.g. `fra`, `nyc`) - **Project ID** (from Console → Settings) -- Hardcode the endpoint and project ID in the file `src/utils/appwrite.ts` (or `.js`) if provided, else leave placeholder and ask the user to provide them. -- Create file `src/utils/appwrite.ts` (or `.js`) with key snippet: + - **API key** with scopes `users.read`, `users.write`, `sessions.write` (Console → Overview → Integrations → API keys) +- Create a `.env` file at the project root: + +```sh +VITE_APPWRITE_ENDPOINT=https://.cloud.appwrite.io/v1 +VITE_APPWRITE_PROJECT_ID= +APPWRITE_API_KEY= +``` + +- The `APPWRITE_API_KEY` is server-only. Never expose it to the browser. + +## Step 4: Mount the auth handler route + +- Create `src/routes/api/appwrite/$.ts`: ```ts -import { Client, Account, ID, type Models } from 'appwrite'; -const endpoint = 'https://.cloud.appwrite.io/v1'; -const projectId = ''; -if (!endpoint || !projectId) throw new Error('Missing Appwrite endpoint and project ID'); -const client = new Client().setEndpoint(endpoint).setProject(projectId); -export const account = new Account(client); -export { ID }; -export type { Models }; +import { createFileRoute } from "@tanstack/react-router"; +import { createAppwriteHandlers } from "@appwrite.io/react/handlers/tanstack"; + +export const Route = createFileRoute("/api/appwrite/$")({ + server: { + handlers: createAppwriteHandlers({ + endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT, + projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: "/api/appwrite", + }), + }, +}); ``` -## Step 4: Build the login route +## Step 5: Build the auth route -- If this is a fresh project, you may replace `src/routes/index.tsx` with an auth UI route. -- If you are working in an existing project, create a new route (e.g., `src/routes/auth.tsx`) instead of overriding the default route. -- The route should render: - - Email/password inputs - - Name input for registration - - Buttons: **Login**, **Register**, **Logout** - - Shows "Logged in as \" when a session exists -- Route scaffold example: +- If this is a fresh project, you may replace `src/routes/index.tsx` with the auth UI route. If you are working in an existing project, create a new route (e.g., `src/routes/auth.tsx`) instead of overriding the default route. +- The route reads SSR auth state via a server function and passes the session into `AppwriteProvider`: ```tsx -import { useState } from 'react'; -import { createFileRoute } from '@tanstack/react-router'; -import { account, ID, type Models } from '../utils/appwrite'; - -export const Route = createFileRoute('/')({ - component: Index +import { useState } from "react"; +import { createFileRoute, useRouter } from "@tanstack/react-router"; +import { createServerFn } from "@tanstack/react-start"; +import { AppwriteProvider, useAuth } from "@appwrite.io/react"; +import { createTanStackServerHelpers } from "@appwrite.io/react/server/tanstack"; + +const getAuthSnapshot = createServerFn({ method: "GET" }).handler(async () => { + const helpers = createTanStackServerHelpers({ + endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT, + projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID, + }); + return { + session: helpers.readSessionCookie() ?? null, + user: await helpers.getLoggedInUser(), + }; }); -function Index() { - const [user, setUser] = useState | null>(null); - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [name, setName] = useState(''); +export const Route = createFileRoute("/")({ + loader: () => getAuthSnapshot(), + component: Page, +}); - async function login(e: string, p: string) { - await account.createEmailPasswordSession({ email: e, password: p }); - setUser(await account.get()); - } +function Page() { + const { session, user } = Route.useLoaderData(); + + return ( + +
+

SSR user: {user?.email ?? "signed out"}

+ +
+
+ ); +} - async function register() { - await account.create({ userId: ID.unique(), email, password, name }); - await login(email, password); - } +function AuthPanel() { + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const router = useRouter(); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [name, setName] = useState(""); - async function logout() { - await account.deleteSession({ sessionId: 'current' }); - setUser(null); - } + if (isLoading) return

Loading...

; + if (user) { return ( -
-

{user ? `Logged in as ${user.name}` : 'Not logged in'}

-
- setEmail(e.target.value)} - /> - setPassword(e.target.value)} - /> - setName(e.target.value)} - /> - - - {user && ( - - )} -
-
+ ); + } + + return ( +
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

} +
+ ); } ``` -## Step 5: Verify environment (ask user to confirm) +## Step 6: Verify environment (ask user to confirm) -- Confirm endpoint and project ID are set in `src/utils/appwrite.ts`. +- Confirm `.env` has the endpoint, project ID, and API key set. - Ensure the Web app platform exists in Appwrite Console with **Hostname** = `localhost`. If missing, guide the user to add it. -## Step 6: Run and test +## Step 7: Run and test - Run: `npm run dev` - Open: `http://localhost:3000` - Test flows: - - Register a new user and auto login works - - Logout then login again -- Surface any Appwrite errors (invalid project, endpoint, CORS/hostname) and fix by guiding updates to `appwrite.ts` and Console settings. + - Sign up a new user, confirm the SSR-rendered user reflects the change after `router.invalidate()` + - Sign out, then sign in again +- Surface any Appwrite errors (invalid project, endpoint, CORS/hostname, missing key scopes) and fix by guiding updates to `.env` and Console settings. ## Deliverables -- A TanStack Start app with working Appwrite auth (register/login/logout) -- Files created/updated: `package.json` (deps), `src/utils/appwrite.ts`, auth route file +- A TanStack Start app with working Appwrite auth using `@appwrite.io/react` +- Files created/updated: `package.json` (deps), `.env`, `src/routes/api/appwrite/$.ts`, auth route file From 44d76b0a22a5b2b28a5692678ddc387e92a8777b Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Mon, 25 May 2026 20:55:39 +0530 Subject: [PATCH 03/61] Document useAuth and useUser refresh helper --- src/routes/docs/products/auth/react/+page.markdoc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/routes/docs/products/auth/react/+page.markdoc b/src/routes/docs/products/auth/react/+page.markdoc index be70c3b9de0..fbc74813e8b 100644 --- a/src/routes/docs/products/auth/react/+page.markdoc +++ b/src/routes/docs/products/auth/react/+page.markdoc @@ -78,7 +78,7 @@ The library exports one combined hook and four focused mutation hooks. All hooks ```tsx import { useAuth } from "@appwrite.io/react"; -const { user, isLoading, error, signIn, signUp, signOut } = useAuth(); +const { user, isLoading, error, refresh, signIn, signUp, signOut } = useAuth(); ``` Returns: @@ -88,6 +88,7 @@ Returns: | `user` | `Models.User \| null \| undefined` | The current user, or `null` if signed out. `undefined` while loading. | | `isLoading` | `boolean` | True while the initial user fetch is in flight. | | `error` | `Error \| null` | First error from the user query or any mutation. | +| `refresh` | `() => Promise` | Refetch the current user and return the resolved value. | | `signIn` | `ReturnType` | Sign-in mutation handle. | | `signUp` | `ReturnType` | Sign-up mutation handle. | | `signOut` | `ReturnType` | Sign-out mutation handle. | @@ -97,7 +98,7 @@ Returns: ```tsx import { useUser } from "@appwrite.io/react"; -const { user, isLoading, error } = useUser(); +const { user, isLoading, error, refresh } = useUser(); ``` Returns: @@ -107,6 +108,7 @@ Returns: | `user` | `Models.User \| null \| undefined` | The current user, or `null` if signed out. `undefined` while loading. | | `isLoading` | `boolean` | True while the user is being fetched. | | `error` | `Error \| null` | Error from the fetch, if one occurred. | +| `refresh` | `() => Promise` | Refetch the current user and return the resolved value. | ## useSignIn {% #use-sign-in %} From 9c2f61bb298e5d66f7d9249dfa5901eb67ad109b Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Mon, 25 May 2026 20:59:16 +0530 Subject: [PATCH 04/61] Address Greptile review on PR #3022 - Fix admin client example: call admin.account.list() instead of dereferencing the Account service - Add multi-route guidance to the TanStack Start quickstart so readers know to move AppwriteProvider into __root.tsx in real apps - Wrap the blog useAuth() snippet in a function component to satisfy the Rules of Hooks - Format prompt.md files per prettier --- .../+page.markdoc | 5 +- .../docs/products/auth/react/+page.markdoc | 2 +- src/routes/docs/quick-starts/nextjs/prompt.md | 191 +++++++++--------- src/routes/docs/quick-starts/react/prompt.md | 90 ++++----- .../quick-starts/tanstack-start/+page.markdoc | 4 + .../quick-starts/tanstack-start/prompt.md | 173 ++++++++-------- 6 files changed, 240 insertions(+), 225 deletions(-) diff --git a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc index 69f02839e76..8e1a23d1853 100644 --- a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc +++ b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc @@ -62,7 +62,10 @@ With the provider in place, every component can pull the current user, sign-in, // App.tsx import { useAuth } from "@appwrite.io/react"; -const { user, signIn, signOut } = useAuth(); +function App() { + const { user, signIn, signOut } = useAuth(); + // render auth UI +} ``` That is the entire client setup. The library handles the service file, the initial account fetching on mount, and the auth context that you would otherwise write by hand. The full walkthrough lives in the [Vite React quickstart](/docs/quick-starts/react). diff --git a/src/routes/docs/products/auth/react/+page.markdoc b/src/routes/docs/products/auth/react/+page.markdoc index fbc74813e8b..ff8498f6a20 100644 --- a/src/routes/docs/products/auth/react/+page.markdoc +++ b/src/routes/docs/products/auth/react/+page.markdoc @@ -288,7 +288,7 @@ const admin = createAdminClient({ apiKey: process.env.APPWRITE_API_KEY!, }); -const users = await admin.account; // node-appwrite Account instance +const users = await admin.account.list(); ``` Never import any `@appwrite.io/react/server/*` module from client code: the entrypoints are marked `server-only` and will throw if bundled into the browser. diff --git a/src/routes/docs/quick-starts/nextjs/prompt.md b/src/routes/docs/quick-starts/nextjs/prompt.md index c0ce195f3c8..689a894c855 100644 --- a/src/routes/docs/quick-starts/nextjs/prompt.md +++ b/src/routes/docs/quick-starts/nextjs/prompt.md @@ -41,13 +41,13 @@ APPWRITE_API_KEY= - Create `app/api/appwrite/[...appwrite]/route.ts` so the library's sign-in, sign-up, sign-out, and OAuth callback endpoints are reachable: ```ts -import { createAppwriteHandlers } from "@appwrite.io/react/handlers/next"; +import { createAppwriteHandlers } from '@appwrite.io/react/handlers/next'; export const { GET, POST } = createAppwriteHandlers({ - endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, - projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, - apiKey: process.env.APPWRITE_API_KEY!, - basePath: "/api/appwrite", + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: '/api/appwrite' }); ``` @@ -56,53 +56,51 @@ export const { GET, POST } = createAppwriteHandlers({ - Create `app/providers.tsx`: ```tsx -"use client"; +'use client'; -import { AppwriteProvider } from "@appwrite.io/react"; +import { AppwriteProvider } from '@appwrite.io/react'; export function Providers({ - session, - children, + session, + children }: { - session?: string | null; - children: React.ReactNode; + session?: string | null; + children: React.ReactNode; }) { - return ( - - {children} - - ); + return ( + + {children} + + ); } ``` - Replace `app/layout.tsx` to read the session cookie server-side and pass it into the provider: ```tsx -import { createNextServerHelpers } from "@appwrite.io/react/server/next"; -import { Providers } from "./providers"; +import { createNextServerHelpers } from '@appwrite.io/react/server/next'; +import { Providers } from './providers'; const appwrite = { - endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, - projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID! }; -export default async function RootLayout({ - children, -}: Readonly<{ children: React.ReactNode }>) { - const helpers = createNextServerHelpers(appwrite); - const session = await helpers.readSessionCookie(); - - return ( - - - {children} - - - ); +export default async function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) { + const helpers = createNextServerHelpers(appwrite); + const session = await helpers.readSessionCookie(); + + return ( + + + {children} + + + ); } ``` @@ -111,80 +109,85 @@ export default async function RootLayout({ - If this is a fresh project you just created, replace `app/page.tsx` to read the user server-side and render the auth panel. If you are working in an existing project, create a new route (e.g. `app/auth/page.tsx`) instead of overriding the default route. ```tsx -import { createNextServerHelpers } from "@appwrite.io/react/server/next"; -import { AuthPanel } from "./auth-panel"; +import { createNextServerHelpers } from '@appwrite.io/react/server/next'; +import { AuthPanel } from './auth-panel'; const appwrite = { - endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, - projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID! }; export default async function Page() { - const helpers = createNextServerHelpers(appwrite); - const user = await helpers.getLoggedInUser(); - - return ( -
-

SSR user: {user?.email ?? "signed out"}

- -
- ); + const helpers = createNextServerHelpers(appwrite); + const user = await helpers.getLoggedInUser(); + + return ( +
+

SSR user: {user?.email ?? 'signed out'}

+ +
+ ); } ``` - Create `app/auth-panel.tsx` for the client-side hook usage: ```tsx -"use client"; +'use client'; -import { useState } from "react"; -import { useAuth } from "@appwrite.io/react"; -import { useRouter } from "next/navigation"; +import { useState } from 'react'; +import { useAuth } from '@appwrite.io/react'; +import { useRouter } from 'next/navigation'; export function AuthPanel() { - const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); - const router = useRouter(); - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [name, setName] = useState(""); - - if (isLoading) return

Loading...

; + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const router = useRouter(); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [name, setName] = useState(''); + + if (isLoading) return

Loading...

; + + if (user) { + return ( + + ); + } - if (user) { return ( - +
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

} +
); - } - - return ( -
- setName(e.target.value)} /> - setEmail(e.target.value)} /> - setPassword(e.target.value)} - /> - - - {error &&

{error.message}

} -
- ); } ``` diff --git a/src/routes/docs/quick-starts/react/prompt.md b/src/routes/docs/quick-starts/react/prompt.md index ad75ced5b44..99798ab284c 100644 --- a/src/routes/docs/quick-starts/react/prompt.md +++ b/src/routes/docs/quick-starts/react/prompt.md @@ -35,21 +35,21 @@ VITE_APPWRITE_PROJECT_ID= - Replace `src/main.tsx` (or `.jsx`) so the entire app is wrapped with `AppwriteProvider`: ```tsx -import { StrictMode } from "react"; -import { createRoot } from "react-dom/client"; -import { AppwriteProvider } from "@appwrite.io/react"; -import App from "./App"; -import "./index.css"; - -createRoot(document.getElementById("root")!).render( - - - - - , +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import { AppwriteProvider } from '@appwrite.io/react'; +import App from './App'; +import './index.css'; + +createRoot(document.getElementById('root')!).render( + + + + + ); ``` @@ -64,41 +64,41 @@ createRoot(document.getElementById("root")!).render( - Use the `useAuth` hook from `@appwrite.io/react`: ```tsx -import { useState } from "react"; -import { useAuth } from "@appwrite.io/react"; +import { useState } from 'react'; +import { useAuth } from '@appwrite.io/react'; export default function App() { - const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [name, setName] = useState(""); + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [name, setName] = useState(''); + + if (isLoading) return

Loading...

; + + if (user) { + return ( +
+

Welcome, {user.name || user.email}

+ +
+ ); + } - if (isLoading) return

Loading...

; - - if (user) { return ( -
-

Welcome, {user.name || user.email}

- -
+
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

} +
); - } - - return ( -
- setName(e.target.value)} /> - setEmail(e.target.value)} /> - setPassword(e.target.value)} - /> - - - {error &&

{error.message}

} -
- ); } ``` diff --git a/src/routes/docs/quick-starts/tanstack-start/+page.markdoc b/src/routes/docs/quick-starts/tanstack-start/+page.markdoc index b658191bdf6..46f284a7907 100644 --- a/src/routes/docs/quick-starts/tanstack-start/+page.markdoc +++ b/src/routes/docs/quick-starts/tanstack-start/+page.markdoc @@ -206,6 +206,10 @@ function AuthPanel() { After every auth mutation, `router.invalidate()` re-runs the loader so the SSR user reflects the new session cookie. +{% info title="Multi-route apps" %} +In a multi-route TanStack Start app, move `AppwriteProvider` (and the auth loader) into `src/routes/__root.tsx` so the TanStack Query cache and auth state persist across navigations. Mounting the provider in a single route works for this quickstart, but resets the cache every time the route changes. +{% /info %} + {% /section %} {% section #step-8 step=8 title="Run your app" %} diff --git a/src/routes/docs/quick-starts/tanstack-start/prompt.md b/src/routes/docs/quick-starts/tanstack-start/prompt.md index d8a8885e373..557807504be 100644 --- a/src/routes/docs/quick-starts/tanstack-start/prompt.md +++ b/src/routes/docs/quick-starts/tanstack-start/prompt.md @@ -40,18 +40,18 @@ APPWRITE_API_KEY= - Create `src/routes/api/appwrite/$.ts`: ```ts -import { createFileRoute } from "@tanstack/react-router"; -import { createAppwriteHandlers } from "@appwrite.io/react/handlers/tanstack"; - -export const Route = createFileRoute("/api/appwrite/$")({ - server: { - handlers: createAppwriteHandlers({ - endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT, - projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID, - apiKey: process.env.APPWRITE_API_KEY!, - basePath: "/api/appwrite", - }), - }, +import { createFileRoute } from '@tanstack/react-router'; +import { createAppwriteHandlers } from '@appwrite.io/react/handlers/tanstack'; + +export const Route = createFileRoute('/api/appwrite/$')({ + server: { + handlers: createAppwriteHandlers({ + endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT, + projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: '/api/appwrite' + }) + } }); ``` @@ -61,89 +61,94 @@ export const Route = createFileRoute("/api/appwrite/$")({ - The route reads SSR auth state via a server function and passes the session into `AppwriteProvider`: ```tsx -import { useState } from "react"; -import { createFileRoute, useRouter } from "@tanstack/react-router"; -import { createServerFn } from "@tanstack/react-start"; -import { AppwriteProvider, useAuth } from "@appwrite.io/react"; -import { createTanStackServerHelpers } from "@appwrite.io/react/server/tanstack"; - -const getAuthSnapshot = createServerFn({ method: "GET" }).handler(async () => { - const helpers = createTanStackServerHelpers({ - endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT, - projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID, - }); - return { - session: helpers.readSessionCookie() ?? null, - user: await helpers.getLoggedInUser(), - }; +import { useState } from 'react'; +import { createFileRoute, useRouter } from '@tanstack/react-router'; +import { createServerFn } from '@tanstack/react-start'; +import { AppwriteProvider, useAuth } from '@appwrite.io/react'; +import { createTanStackServerHelpers } from '@appwrite.io/react/server/tanstack'; + +const getAuthSnapshot = createServerFn({ method: 'GET' }).handler(async () => { + const helpers = createTanStackServerHelpers({ + endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT, + projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID + }); + return { + session: helpers.readSessionCookie() ?? null, + user: await helpers.getLoggedInUser() + }; }); -export const Route = createFileRoute("/")({ - loader: () => getAuthSnapshot(), - component: Page, +export const Route = createFileRoute('/')({ + loader: () => getAuthSnapshot(), + component: Page }); function Page() { - const { session, user } = Route.useLoaderData(); - - return ( - -
-

SSR user: {user?.email ?? "signed out"}

- -
-
- ); + const { session, user } = Route.useLoaderData(); + + return ( + +
+

SSR user: {user?.email ?? 'signed out'}

+ +
+
+ ); } function AuthPanel() { - const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); - const router = useRouter(); - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [name, setName] = useState(""); - - if (isLoading) return

Loading...

; + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const router = useRouter(); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [name, setName] = useState(''); + + if (isLoading) return

Loading...

; + + if (user) { + return ( + + ); + } - if (user) { return ( - +
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

} +
); - } - - return ( -
- setName(e.target.value)} /> - setEmail(e.target.value)} /> - setPassword(e.target.value)} - /> - - - {error &&

{error.message}

} -
- ); } ``` From d96ebb4b6f26175eec3c2c62d4dfdadd24520add Mon Sep 17 00:00:00 2001 From: adityaoberai Date: Thu, 4 Jun 2026 01:33:36 +0530 Subject: [PATCH 05/61] Bifurcate Advanced > Platform docs into other relevant sections --- STYLE.md | 5 +- src/partials/account-vs-user.md | 2 +- src/partials/auth-security.md | 4 +- src/redirects.json | 142 +++++++++++++- src/routes/(init)/init/+page.svelte | 2 +- src/routes/docs/Sidebar.svelte | 15 +- .../advanced/api-integration/+layout.svelte | 61 ++++++ .../advanced/api-integration/+page.markdoc | 43 +++++ .../error-handling/+page.markdoc | 2 +- .../events/+page.markdoc | 2 +- .../release-policy/+page.markdoc | 0 .../response-codes/+page.markdoc | 2 +- .../webhooks/+page.markdoc | 8 +- .../docs/advanced/billing/+layout.svelte | 106 +++++++++++ .../docs/advanced/billing/+page.markdoc | 91 +++++++++ .../{platform => billing}/abuse/+page.markdoc | 0 .../compute/+page.markdoc | 0 .../database-reads-and-writes/+page.markdoc | 0 .../enterprise/+page.markdoc | 0 .../fair-use-policy/+page.markdoc | 0 .../{platform => billing}/free/+page.markdoc | 0 .../image-transformations/+page.markdoc | 0 .../{platform => billing}/oss/+page.markdoc | 0 .../payments}/+page.markdoc | 0 .../phone-otp/+page.markdoc | 0 .../{platform => billing}/pro/+page.markdoc | 0 .../refund-policy/+page.markdoc | 2 +- .../{platform => billing}/scale/+page.markdoc | 0 .../support-sla/+page.markdoc | 0 .../uptime-sla/+page.markdoc | 0 .../docs/advanced/integration/+layout.svelte | 30 --- .../docs/advanced/integration/+page.markdoc | 6 - .../migrations/firebase/+page.markdoc | 2 +- .../advanced/migrations/nhost/+page.markdoc | 2 +- .../migrations/supabase/+page.markdoc | 2 +- .../docs/advanced/platform/+layout.svelte | 180 ------------------ .../docs/advanced/platform/+page.markdoc | 123 ------------ .../docs/advanced/security/+layout.svelte | 30 +++ .../docs/advanced/security/+page.markdoc | 42 +++- .../security/abuse-protection/+page.markdoc | 2 +- .../api-keys/+page.markdoc | 2 +- .../security/audit-logs/+page.markdoc | 2 +- .../dev-keys/+page.markdoc | 6 +- .../environment-variables/+page.markdoc | 2 +- .../advanced/security/https/+page.markdoc | 2 +- .../permissions/+page.markdoc | 2 +- .../rate-limits/+page.markdoc | 2 +- .../docs/advanced/security/tls/+page.markdoc | 2 +- .../production/debugging/+page.markdoc | 2 +- .../production/rate-limits/+page.markdoc | 2 +- src/routes/docs/apis/realtime/+page.markdoc | 4 +- .../realtime/authentication/+page.markdoc | 2 +- .../docs/apis/realtime/payload/+page.markdoc | 2 +- .../apis/realtime/presences/+page.markdoc | 6 +- src/routes/docs/apis/rest/+page.markdoc | 4 +- src/routes/docs/products/auth/+layout.svelte | 8 + .../docs/products/auth/accounts/+page.markdoc | 2 +- .../docs/products/auth/jwt/+page.markdoc | 4 +- .../docs/products/auth/labels/+page.markdoc | 2 +- .../auth}/message-templates/+page.markdoc | 2 +- .../products/auth/phone-sms/+page.markdoc | 2 +- .../products/auth/presences/+page.markdoc | 8 +- .../auth}/roles/+page.markdoc | 0 .../auth/server-side-rendering/+page.markdoc | 8 +- .../products/auth/team-invites/+page.markdoc | 2 +- .../docs/products/auth/teams/+page.markdoc | 2 +- .../databases/databases/+page.markdoc | 2 +- .../legacy/collections/+page.markdoc | 2 +- .../databases/legacy/databases/+page.markdoc | 2 +- .../legacy/permissions/+page.markdoc | 6 +- .../databases/permissions/+page.markdoc | 6 +- .../products/databases/tables/+page.markdoc | 2 +- .../functions/deployments/+page.markdoc | 4 +- .../products/functions/develop/+page.markdoc | 2 +- .../environment-variables/+page.markdoc | 6 +- .../products/functions/execute/+page.markdoc | 6 +- .../functions/executions/+page.markdoc | 2 +- .../functions/functions/+page.markdoc | 10 +- .../products/messaging/topics/+page.markdoc | 2 +- .../docs/products/network/+layout.svelte | 4 + .../network/caa-records/+page.markdoc | 2 +- .../network}/custom-domains/+page.markdoc | 0 .../products/sites/deployments/+page.markdoc | 4 +- .../docs/products/sites/develop/+page.markdoc | 4 +- .../sites/environment-variables/+page.markdoc | 6 +- .../products/storage/buckets/+page.markdoc | 2 +- .../storage/file-tokens/+page.markdoc | 8 +- .../storage/permissions/+page.markdoc | 4 +- .../docs/quick-starts/flutter/+page.markdoc | 2 +- src/routes/docs/references/+page.markdoc | 8 +- .../[service]/(components)/RateLimits.svelte | 2 +- .../[service]/descriptions/presences.md | 2 +- .../[service]/descriptions/storage.md | 2 +- .../[service]/descriptions/teams.md | 2 +- .../docs/references/quick-start/+page.markdoc | 4 +- src/routes/docs/sdks/+page.markdoc | 2 +- .../tooling/ai/responsible-ai/+page.markdoc | 2 +- .../tooling/command-center/+layout.svelte | 25 ++- .../command-center}/shortcuts/+page.markdoc | 0 .../non-interactive/+page.markdoc | 2 +- .../resources/webhooks/+page.markdoc | 4 +- .../step-5/+page.markdoc | 2 +- src/routes/llms-full.txt/+server.ts | 2 +- src/routes/llms.txt/+server.ts | 2 +- src/routes/pricing/compare-plans.svelte | 4 +- src/routes/pricing/faq.svelte | 6 +- .../products/auth/(components)/Access.svelte | 2 +- src/routes/startups/faq.svelte | 2 +- src/routes/terms/+page.markdoc | 2 +- 109 files changed, 676 insertions(+), 477 deletions(-) create mode 100644 src/routes/docs/advanced/api-integration/+layout.svelte create mode 100644 src/routes/docs/advanced/api-integration/+page.markdoc rename src/routes/docs/advanced/{platform => api-integration}/error-handling/+page.markdoc (97%) rename src/routes/docs/advanced/{platform => api-integration}/events/+page.markdoc (98%) rename src/routes/docs/advanced/{platform => api-integration}/release-policy/+page.markdoc (100%) rename src/routes/docs/advanced/{platform => api-integration}/response-codes/+page.markdoc (99%) rename src/routes/docs/advanced/{platform => api-integration}/webhooks/+page.markdoc (99%) create mode 100644 src/routes/docs/advanced/billing/+layout.svelte create mode 100644 src/routes/docs/advanced/billing/+page.markdoc rename src/routes/docs/advanced/{platform => billing}/abuse/+page.markdoc (100%) rename src/routes/docs/advanced/{platform => billing}/compute/+page.markdoc (100%) rename src/routes/docs/advanced/{platform => billing}/database-reads-and-writes/+page.markdoc (100%) rename src/routes/docs/advanced/{platform => billing}/enterprise/+page.markdoc (100%) rename src/routes/docs/advanced/{platform => billing}/fair-use-policy/+page.markdoc (100%) rename src/routes/docs/advanced/{platform => billing}/free/+page.markdoc (100%) rename src/routes/docs/advanced/{platform => billing}/image-transformations/+page.markdoc (100%) rename src/routes/docs/advanced/{platform => billing}/oss/+page.markdoc (100%) rename src/routes/docs/advanced/{platform/billing => billing/payments}/+page.markdoc (100%) rename src/routes/docs/advanced/{platform => billing}/phone-otp/+page.markdoc (100%) rename src/routes/docs/advanced/{platform => billing}/pro/+page.markdoc (100%) rename src/routes/docs/advanced/{platform => billing}/refund-policy/+page.markdoc (97%) rename src/routes/docs/advanced/{platform => billing}/scale/+page.markdoc (100%) rename src/routes/docs/advanced/{platform => billing}/support-sla/+page.markdoc (100%) rename src/routes/docs/advanced/{platform => billing}/uptime-sla/+page.markdoc (100%) delete mode 100644 src/routes/docs/advanced/integration/+layout.svelte delete mode 100644 src/routes/docs/advanced/integration/+page.markdoc delete mode 100644 src/routes/docs/advanced/platform/+layout.svelte delete mode 100644 src/routes/docs/advanced/platform/+page.markdoc rename src/routes/docs/advanced/{platform => security}/api-keys/+page.markdoc (99%) rename src/routes/docs/advanced/{platform => security}/dev-keys/+page.markdoc (93%) rename src/routes/docs/advanced/{platform => security}/environment-variables/+page.markdoc (99%) rename src/routes/docs/advanced/{platform => security}/permissions/+page.markdoc (99%) rename src/routes/docs/advanced/{platform => security}/rate-limits/+page.markdoc (98%) rename src/routes/docs/{advanced/platform => products/auth}/message-templates/+page.markdoc (99%) rename src/routes/docs/{advanced/platform => products/auth}/roles/+page.markdoc (100%) rename src/routes/docs/{advanced/platform => products/network}/custom-domains/+page.markdoc (100%) rename src/routes/docs/{advanced/platform => tooling/command-center}/shortcuts/+page.markdoc (100%) diff --git a/STYLE.md b/STYLE.md index ece9cd70832..d731a6b549b 100644 --- a/STYLE.md +++ b/STYLE.md @@ -57,7 +57,8 @@ Tooling section: Advanced section: -- [Platform](https://appwrite.io/docs/advanced/platform) +- [Billing](https://appwrite.io/docs/advanced/billing) +- [API integration](https://appwrite.io/docs/advanced/api-integration) - [Migrations](https://appwrite.io/docs/advanced/migrations) - [Self-hosting](https://appwrite.io/docs/advanced/self-hosting) - [Security](https://appwrite.io/docs/advanced/security) @@ -214,7 +215,7 @@ Split content such that each piece makes sense without reading dependents or exp - [ ] Point Cloud to new version in [src/routes/docs/references/[version]/[platform]/[service]/+page.server.ts](src/routes/docs/references/[version]/[platform]/[service]/+page.server.ts) - [ ] Update install command in [/workspaces/website/src/routes/docs/advanced/self-hosting/+page.markdoc](/workspaces/website/src/routes/docs/advanced/self-hosting/+page.markdoc) - [ ] Update events [src/partials/[product]-events.md](src/partials/) -- [ ] Update response code [src/routes/docs/advanced/platform/response-codes/+page.markdoc](src/routes/docs/advanced/platform/response-codes/+page.markdoc) +- [ ] Update response code [src/routes/docs/advanced/api-integration/response-codes/+page.markdoc](src/routes/docs/advanced/api-integration/response-codes/+page.markdoc) - [ ] Bump latest SDK versions in SDKs page, quick start, and tutorials - [ ] Create new sections for new products - [ ] Create new concept and journey pages for new features diff --git a/src/partials/account-vs-user.md b/src/partials/account-vs-user.md index 4a7c3949bbf..c189d9f8f85 100644 --- a/src/partials/account-vs-user.md +++ b/src/partials/account-vs-user.md @@ -1,7 +1,7 @@ {% info title="Account vs Users API" %} The Account API is the API you should use in your **client applications** with [Client SDKs](/docs/sdks#client) like web, Flutter, mobile, and native apps. Account API creates sessions, which represent an authenticated user and is attached to a user's [account](/docs/products/auth/accounts). -Sessions respect [permissions](/docs/advanced/platform/permissions), which means users can only access resources if they have been granted the correct permissions. +Sessions respect [permissions](/docs/advanced/security/permissions), which means users can only access resources if they have been granted the correct permissions. The Users API is a dedicated API for managing users from an admin's perspective. It should be used with backend or server-side applications with [Server SDKs](/docs/sdks#server). Users API uses API keys instead of sessions. diff --git a/src/partials/auth-security.md b/src/partials/auth-security.md index 25a18f44e6d..4494b372c61 100644 --- a/src/partials/auth-security.md +++ b/src/partials/auth-security.md @@ -22,7 +22,7 @@ You can change the session limit in the **Security** tab of the Auth Service in # Permissions {% #permissions %} Security is very important to protect users' data and privacy. -Appwrite uses a [permissions model](/docs/advanced/platform/permissions) coupled with user sessions to ensure users need correct permissions to access resources. +Appwrite uses a [permissions model](/docs/advanced/security/permissions) coupled with user sessions to ensure users need correct permissions to access resources. With all Appwrite services, including databases and storage, access is granted at the collection, bucket, document, or file level. These permissions are enforced for client SDKs and server SDKs when using JWT, but are ignored when using a server SDK with an API key. @@ -34,7 +34,7 @@ Password history can be enabled in the Auth service's **Security** tab on the Ap # Password dictionary {% #password-dictionary %} -Password dictionary protects users from using bad passwords. It compares the user's password to the [10,000 most common passwords](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10k-most-common.txt) and throws an error if there's a match. Together with [rate limits](/docs/advanced/platform/rate-limits), password dictionary will significantly reduce the chance of a malicious actor guessing user passwords. +Password dictionary protects users from using bad passwords. It compares the user's password to the [10,000 most common passwords](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10k-most-common.txt) and throws an error if there's a match. Together with [rate limits](/docs/advanced/security/rate-limits), password dictionary will significantly reduce the chance of a malicious actor guessing user passwords. Password dictionary can be enabled in the Auth service's **Security** tab on the Appwrite Console. diff --git a/src/redirects.json b/src/redirects.json index 85d37658dec..9ca53703efe 100644 --- a/src/redirects.json +++ b/src/redirects.json @@ -201,15 +201,15 @@ }, { "link": "/docs/keys", - "redirect": "/docs/advanced/platform/api-keys" + "redirect": "/docs/advanced/security/api-keys" }, { "link": "/docs/permissions", - "redirect": "/docs/advanced/platform/permissions" + "redirect": "/docs/advanced/security/permissions" }, { "link": "/docs/events", - "redirect": "/docs/advanced/platform/events" + "redirect": "/docs/advanced/api-integration/events" }, { "link": "/docs/queries", @@ -221,23 +221,23 @@ }, { "link": "/docs/webhooks", - "redirect": "/docs/advanced/platform/webhooks" + "redirect": "/docs/advanced/api-integration/webhooks" }, { "link": "/docs/custom-domains", - "redirect": "/docs/advanced/platform/custom-domains" + "redirect": "/docs/products/network/custom-domains" }, { "link": "/docs/email-and-sms-templates", - "redirect": "/docs/advanced/platform/message-templates" + "redirect": "/docs/products/auth/message-templates" }, { "link": "/docs/response-codes", - "redirect": "/docs/advanced/platform/response-codes" + "redirect": "/docs/advanced/api-integration/response-codes" }, { "link": "/docs/rate-limits", - "redirect": "/docs/advanced/platform/rate-limits" + "redirect": "/docs/advanced/security/rate-limits" }, { "link": "/docs/configuration", @@ -445,7 +445,7 @@ }, { "link": "/docs/permissions/", - "redirect": "/docs/advanced/platform/permissions" + "redirect": "/docs/advanced/security/permissions" }, { "link": "/docs/models/bucket", @@ -867,5 +867,129 @@ { "link": "/heroes", "redirect": "/" + }, + { + "link": "/docs/advanced/platform", + "redirect": "/docs" + }, + { + "link": "/docs/advanced/platform/billing", + "redirect": "/docs/advanced/billing/payments" + }, + { + "link": "/docs/advanced/platform/free", + "redirect": "/docs/advanced/billing/free" + }, + { + "link": "/docs/advanced/platform/pro", + "redirect": "/docs/advanced/billing/pro" + }, + { + "link": "/docs/advanced/platform/scale", + "redirect": "/docs/advanced/billing/scale" + }, + { + "link": "/docs/advanced/platform/enterprise", + "redirect": "/docs/advanced/billing/enterprise" + }, + { + "link": "/docs/advanced/platform/oss", + "redirect": "/docs/advanced/billing/oss" + }, + { + "link": "/docs/advanced/platform/compute", + "redirect": "/docs/advanced/billing/compute" + }, + { + "link": "/docs/advanced/platform/phone-otp", + "redirect": "/docs/advanced/billing/phone-otp" + }, + { + "link": "/docs/advanced/platform/image-transformations", + "redirect": "/docs/advanced/billing/image-transformations" + }, + { + "link": "/docs/advanced/platform/database-reads-and-writes", + "redirect": "/docs/advanced/billing/database-reads-and-writes" + }, + { + "link": "/docs/advanced/platform/support-sla", + "redirect": "/docs/advanced/billing/support-sla" + }, + { + "link": "/docs/advanced/platform/uptime-sla", + "redirect": "/docs/advanced/billing/uptime-sla" + }, + { + "link": "/docs/advanced/platform/fair-use-policy", + "redirect": "/docs/advanced/billing/fair-use-policy" + }, + { + "link": "/docs/advanced/platform/abuse", + "redirect": "/docs/advanced/billing/abuse" + }, + { + "link": "/docs/advanced/platform/refund-policy", + "redirect": "/docs/advanced/billing/refund-policy" + }, + { + "link": "/docs/advanced/platform/events", + "redirect": "/docs/advanced/api-integration/events" + }, + { + "link": "/docs/advanced/platform/webhooks", + "redirect": "/docs/advanced/api-integration/webhooks" + }, + { + "link": "/docs/advanced/platform/response-codes", + "redirect": "/docs/advanced/api-integration/response-codes" + }, + { + "link": "/docs/advanced/platform/error-handling", + "redirect": "/docs/advanced/api-integration/error-handling" + }, + { + "link": "/docs/advanced/platform/release-policy", + "redirect": "/docs/advanced/api-integration/release-policy" + }, + { + "link": "/docs/advanced/platform/permissions", + "redirect": "/docs/advanced/security/permissions" + }, + { + "link": "/docs/advanced/platform/rate-limits", + "redirect": "/docs/advanced/security/rate-limits" + }, + { + "link": "/docs/advanced/platform/api-keys", + "redirect": "/docs/advanced/security/api-keys" + }, + { + "link": "/docs/advanced/platform/dev-keys", + "redirect": "/docs/advanced/security/dev-keys" + }, + { + "link": "/docs/advanced/platform/roles", + "redirect": "/docs/products/auth/roles" + }, + { + "link": "/docs/advanced/platform/message-templates", + "redirect": "/docs/products/auth/message-templates" + }, + { + "link": "/docs/advanced/platform/custom-domains", + "redirect": "/docs/products/network/custom-domains" + }, + { + "link": "/docs/advanced/platform/shortcuts", + "redirect": "/docs/tooling/command-center/shortcuts" + }, + { + "link": "/docs/advanced/platform/environment-variables", + "redirect": "/docs/advanced/security/environment-variables" + }, + { + "link": "/docs/advanced/integration", + "redirect": "/docs/advanced/api-integration" } ] diff --git a/src/routes/(init)/init/+page.svelte b/src/routes/(init)/init/+page.svelte index c3f5174c34e..f7d440da5c4 100644 --- a/src/routes/(init)/init/+page.svelte +++ b/src/routes/(init)/init/+page.svelte @@ -127,7 +127,7 @@ }, { title: 'Dev Keys', - url: '/docs/advanced/platform/dev-keys', + url: '/docs/advanced/security/dev-keys', type: 'Docs', label: 'Visit docs' } diff --git a/src/routes/docs/Sidebar.svelte b/src/routes/docs/Sidebar.svelte index c03804aa501..aa4af364e4a 100644 --- a/src/routes/docs/Sidebar.svelte +++ b/src/routes/docs/Sidebar.svelte @@ -152,7 +152,8 @@ { label: 'Command Center', href: '/docs/tooling/command-center', - icon: 'web-icon-command' + icon: 'web-icon-command', + isParent: true }, { label: 'The Appwriter', @@ -165,9 +166,9 @@ label: 'Advanced', items: [ { - label: 'Platform', - href: '/docs/advanced/platform', - icon: 'web-icon-platform', + label: 'Billing', + href: '/docs/advanced/billing', + icon: 'icon-credit-card', isParent: true }, { @@ -176,6 +177,12 @@ icon: 'icon-share', isParent: true }, + { + label: 'API Integration', + href: '/docs/advanced/api-integration', + icon: 'icon-switch-horizontal', + isParent: true + }, { label: 'Migrations', href: '/docs/advanced/migrations', diff --git a/src/routes/docs/advanced/api-integration/+layout.svelte b/src/routes/docs/advanced/api-integration/+layout.svelte new file mode 100644 index 00000000000..419f18cda54 --- /dev/null +++ b/src/routes/docs/advanced/api-integration/+layout.svelte @@ -0,0 +1,61 @@ + + + + + + diff --git a/src/routes/docs/advanced/api-integration/+page.markdoc b/src/routes/docs/advanced/api-integration/+page.markdoc new file mode 100644 index 00000000000..9419cab0efd --- /dev/null +++ b/src/routes/docs/advanced/api-integration/+page.markdoc @@ -0,0 +1,43 @@ +--- +layout: article +title: API integration +description: Integrate Appwrite with your apps using events and webhooks, and learn how Appwrite's APIs report response codes and errors. +--- + +Appwrite is designed to integrate with both your frontend and backend apps. Learn how to react to platform events, keep external systems in sync with webhooks, and handle the response codes and errors returned by Appwrite's APIs. + +# Events and webhooks {% #events-and-webhooks %} + +React to events that occur across your Appwrite project and notify external systems. + +{% cards %} +{% cards_item href="/docs/advanced/api-integration/events" title="Events" %} +Appwrite allows you to react to events that occur on the platform. +{% /cards_item %} + +{% cards_item href="/docs/advanced/api-integration/webhooks" title="Webhooks" %} +Use webhooks to update backend integrations about Appwrite events. +{% /cards_item %} +{% /cards %} + +# Error reference {% #error-reference %} + +Understand how Appwrite's APIs report success and failure, and how to handle errors gracefully. + +{% cards %} +{% cards_item href="/docs/advanced/api-integration/response-codes" title="Response codes" %} +Learn about response codes and errors returned by Appwrite APIs. +{% /cards_item %} + +{% cards_item href="/docs/advanced/api-integration/error-handling" title="Error handling" %} +Best practices for handling Appwrite errors in your applications. +{% /cards_item %} +{% /cards %} + +# Policies {% #policies %} + +{% cards %} +{% cards_item href="/docs/advanced/api-integration/release-policy" title="Release policy" %} +Understand how Appwrite releases and versions its platforms and APIs. +{% /cards_item %} +{% /cards %} diff --git a/src/routes/docs/advanced/platform/error-handling/+page.markdoc b/src/routes/docs/advanced/api-integration/error-handling/+page.markdoc similarity index 97% rename from src/routes/docs/advanced/platform/error-handling/+page.markdoc rename to src/routes/docs/advanced/api-integration/error-handling/+page.markdoc index 1e6102f9f2e..fabb96d3f55 100644 --- a/src/routes/docs/advanced/platform/error-handling/+page.markdoc +++ b/src/routes/docs/advanced/api-integration/error-handling/+page.markdoc @@ -53,7 +53,7 @@ Here are some examples of how you might map Appwrite error types to user-friendl # Complete list of error types -Appwrite provides a comprehensive list of error types organized by category. For a complete reference, see the [Response codes](/docs/advanced/platform/response-codes#error-types) documentation. +Appwrite provides a comprehensive list of error types organized by category. For a complete reference, see the [Response codes](/docs/advanced/api-integration/response-codes#error-types) documentation. # Recommended practices diff --git a/src/routes/docs/advanced/platform/events/+page.markdoc b/src/routes/docs/advanced/api-integration/events/+page.markdoc similarity index 98% rename from src/routes/docs/advanced/platform/events/+page.markdoc rename to src/routes/docs/advanced/api-integration/events/+page.markdoc index 6adfccac4e2..b79bfb922d1 100644 --- a/src/routes/docs/advanced/platform/events/+page.markdoc +++ b/src/routes/docs/advanced/api-integration/events/+page.markdoc @@ -6,7 +6,7 @@ description: Harness the power of events in Appwrite. Explore event-driven archi Appwrite provides a variety of events that allows your application to react to changes as they happen. An event will fire when a change occurs in your Appwrite project, like when a new user registers or a new file is uploaded to Appwrite. -You can subscribe to these events with Appwrite [Functions](/docs/products/functions), [Realtime](/docs/apis/realtime), or [Webhooks](/docs/advanced/platform/webhooks). +You can subscribe to these events with Appwrite [Functions](/docs/products/functions), [Realtime](/docs/apis/realtime), or [Webhooks](/docs/advanced/api-integration/webhooks). You can subscribe to events for specific resources using their ID or subscribe to changes of all resources of the same type by using a wildcard character * instead of an ID. You can also filter for events of specific actions like create, update, upsert, or delete. diff --git a/src/routes/docs/advanced/platform/release-policy/+page.markdoc b/src/routes/docs/advanced/api-integration/release-policy/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/release-policy/+page.markdoc rename to src/routes/docs/advanced/api-integration/release-policy/+page.markdoc diff --git a/src/routes/docs/advanced/platform/response-codes/+page.markdoc b/src/routes/docs/advanced/api-integration/response-codes/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/platform/response-codes/+page.markdoc rename to src/routes/docs/advanced/api-integration/response-codes/+page.markdoc index e46772d8faf..a0e462810af 100644 --- a/src/routes/docs/advanced/platform/response-codes/+page.markdoc +++ b/src/routes/docs/advanced/api-integration/response-codes/+page.markdoc @@ -26,7 +26,7 @@ Appwrite uses conventional HTTP response codes to indicate the success or failur | 409 | Conflict | This response is sent when a request conflicts with the current state of the server. This status code will usually appear when you're trying to create an already existing resource. | | 413 | Payload Too Large | This indicates that the request entity is larger than limits defined by server. This status code will usually appear happen when uploading a file or function that is too large | | 416 | Invalid Range | Invalid value in the range or content-range headers. Usually returned while uploading or downloading files using the range header but the provided range value is not valid. | -| 429 | Too Many Requests | Returned in when a request cannot be served due to the application's rate limit having been exhausted for the resource. See [Rate Limits](/docs/advanced/platform/rate-limits). | +| 429 | Too Many Requests | Returned in when a request cannot be served due to the application's rate limit having been exhausted for the resource. See [Rate Limits](/docs/advanced/security/rate-limits). | | 500 | Internal Server Error | Something is broken. Contact our [team](/support), or raise a [GitHub issue](https://github.com/appwrite/appwrite/issues/new). | | 501 | Not Implemented | The feature is not implemented. Usually returned when the project owner has disabled an auth method or an entire service. | | 503 | Service Unavailable | The Appwrite servers are up but overloaded with requests. Try again later. | diff --git a/src/routes/docs/advanced/platform/webhooks/+page.markdoc b/src/routes/docs/advanced/api-integration/webhooks/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/platform/webhooks/+page.markdoc rename to src/routes/docs/advanced/api-integration/webhooks/+page.markdoc index 2294d47726e..b194dafab41 100644 --- a/src/routes/docs/advanced/platform/webhooks/+page.markdoc +++ b/src/routes/docs/advanced/api-integration/webhooks/+page.markdoc @@ -27,7 +27,7 @@ To add a webhook from the Appwrite Console: # Manage webhooks with a Server SDK {% #manage-webhooks-with-a-server-sdk %} -You can also manage webhooks programmatically using a Server SDK. This requires an API key with the `webhooks.read` and `webhooks.write` [scopes](/docs/advanced/platform/api-keys#scopes). +You can also manage webhooks programmatically using a Server SDK. This requires an API key with the `webhooks.read` and `webhooks.write` [scopes](/docs/advanced/security/api-keys#scopes). ## Create a webhook {% #create-a-webhook %} @@ -1474,7 +1474,7 @@ async fn main() -> Result<(), Box> { # Payload {% #payload %} -Each event type has a specific payload format with the relevant event information. All event payloads mirror the payloads for the API payload which parallel to the [event types](/docs/advanced/platform/events). +Each event type has a specific payload format with the relevant event information. All event payloads mirror the payloads for the API payload which parallel to the [event types](/docs/advanced/api-integration/events). # Headers {% #headers %} @@ -1484,7 +1484,7 @@ HTTP requests made to your webhook's configured URL endpoint will contain severa |--------|-------------| | X-Appwrite-Webhook-Id | The ID of the Webhook who triggered the event. | | X-Appwrite-Webhook-Events | Names of the events that triggered this delivery. | -| X-Appwrite-Webhook-Name | Name of the webhook as specified in your app settings and [events list](/docs/advanced/platform/events). | +| X-Appwrite-Webhook-Name | Name of the webhook as specified in your app settings and [events list](/docs/advanced/api-integration/events). | | X-Appwrite-Webhook-User-Id | The user ID of the user who triggered the event. Returns an empty string if an API key triggered the event. Note that events like `account.create` or `account.sessions.create` are performed by guest users and will not return any user ID. If you still need the user ID for these events, you can find it in the event payload. | | X-Appwrite-Webhook-Project-Id | The ID of the project who owns the Webhook and API call. | | X-Appwrite-Webhook-Signature | The HMAC-SHA1 signature of the payload. This is used to verify the authenticity of the payload. | @@ -1704,4 +1704,4 @@ You can specify one or many events to subscribe to with webhooks. {% /accordion_item %} {% /accordion %} -[Learn more about events](/docs/advanced/platform/events) +[Learn more about events](/docs/advanced/api-integration/events) diff --git a/src/routes/docs/advanced/billing/+layout.svelte b/src/routes/docs/advanced/billing/+layout.svelte new file mode 100644 index 00000000000..584592ca24e --- /dev/null +++ b/src/routes/docs/advanced/billing/+layout.svelte @@ -0,0 +1,106 @@ + + + + + + diff --git a/src/routes/docs/advanced/billing/+page.markdoc b/src/routes/docs/advanced/billing/+page.markdoc new file mode 100644 index 00000000000..4aa6db90442 --- /dev/null +++ b/src/routes/docs/advanced/billing/+page.markdoc @@ -0,0 +1,91 @@ +--- +layout: article +title: Billing +description: Understand Appwrite's plans, add-ons, service level agreements, and billing policies. +--- + +Learn which plan best suits your organization, explore optional add-ons, and understand Appwrite's service level agreements and billing policies. + +# Plans {% #plans %} + +Learn which plan best suits your organization and how to manage billing. + +{% cards %} +{% cards_item href="/docs/advanced/billing/payments" title="Billing" %} +Learn to manage your billing information. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/free" title="Free" %} +Learn about Appwrite Free plan. Free plan for hobby projects and learners. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/pro" title="Pro" %} +Learn about Appwrite Pro, for growing organizations that need to scale. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/scale" title="Scale" %} +Learn about Appwrite Scale, for teams and agencies scaling their applications. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/enterprise" title="Enterprise" %} +Learn about Appwrite Enterprise, for large organizations with advanced needs. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/oss" title="Open source" %} +Appwrite provides special plans for open source projects. +{% /cards_item %} +{% /cards %} + +# Add ons {% #add-ons %} + +Learn about additional features and functionalities that Appwrite offers. + +{% cards %} +{% cards_item href="/docs/advanced/billing/compute" title="Compute" %} +CPU and memory for Functions and Sites, including build and runtime specs. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/phone-otp" title="Phone OTP" %} +Learn how Appwrite handles SMS-based OTP authentication. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/image-transformations" title="Image Transformations" %} +Learn how to transform images dynamically with Appwrite. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/database-reads-and-writes" title="Database Reads and Writes" %} +Learn how Appwrite handles database reads and writes. +{% /cards_item %} +{% /cards %} + +# Service level agreements {% #slas %} + +Understand the service level agreements available on Appwrite's paid plans. + +{% cards %} +{% cards_item href="/docs/advanced/billing/support-sla" title="Support SLA" %} +Learn about Appwrite's support response time commitments. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/uptime-sla" title="Uptime SLA" %} +Learn about Appwrite's uptime commitments. +{% /cards_item %} +{% /cards %} + +# Policies {% #policies %} + +Understand the policies that govern usage and billing on Appwrite. + +{% cards %} +{% cards_item href="/docs/advanced/billing/fair-use-policy" title="Fair use" %} +Understand Appwrite's usage limits, prohibited activities, and enforcement actions. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/abuse" title="Abuse" %} +Guidelines on abusive behavior, prohibited activities, and reporting mechanisms. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/refund-policy" title="Refund" %} +Learn about Appwrite's refund policy, eligibility criteria, and request process. +{% /cards_item %} +{% /cards %} diff --git a/src/routes/docs/advanced/platform/abuse/+page.markdoc b/src/routes/docs/advanced/billing/abuse/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/abuse/+page.markdoc rename to src/routes/docs/advanced/billing/abuse/+page.markdoc diff --git a/src/routes/docs/advanced/platform/compute/+page.markdoc b/src/routes/docs/advanced/billing/compute/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/compute/+page.markdoc rename to src/routes/docs/advanced/billing/compute/+page.markdoc diff --git a/src/routes/docs/advanced/platform/database-reads-and-writes/+page.markdoc b/src/routes/docs/advanced/billing/database-reads-and-writes/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/database-reads-and-writes/+page.markdoc rename to src/routes/docs/advanced/billing/database-reads-and-writes/+page.markdoc diff --git a/src/routes/docs/advanced/platform/enterprise/+page.markdoc b/src/routes/docs/advanced/billing/enterprise/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/enterprise/+page.markdoc rename to src/routes/docs/advanced/billing/enterprise/+page.markdoc diff --git a/src/routes/docs/advanced/platform/fair-use-policy/+page.markdoc b/src/routes/docs/advanced/billing/fair-use-policy/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/fair-use-policy/+page.markdoc rename to src/routes/docs/advanced/billing/fair-use-policy/+page.markdoc diff --git a/src/routes/docs/advanced/platform/free/+page.markdoc b/src/routes/docs/advanced/billing/free/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/free/+page.markdoc rename to src/routes/docs/advanced/billing/free/+page.markdoc diff --git a/src/routes/docs/advanced/platform/image-transformations/+page.markdoc b/src/routes/docs/advanced/billing/image-transformations/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/image-transformations/+page.markdoc rename to src/routes/docs/advanced/billing/image-transformations/+page.markdoc diff --git a/src/routes/docs/advanced/platform/oss/+page.markdoc b/src/routes/docs/advanced/billing/oss/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/oss/+page.markdoc rename to src/routes/docs/advanced/billing/oss/+page.markdoc diff --git a/src/routes/docs/advanced/platform/billing/+page.markdoc b/src/routes/docs/advanced/billing/payments/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/billing/+page.markdoc rename to src/routes/docs/advanced/billing/payments/+page.markdoc diff --git a/src/routes/docs/advanced/platform/phone-otp/+page.markdoc b/src/routes/docs/advanced/billing/phone-otp/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/phone-otp/+page.markdoc rename to src/routes/docs/advanced/billing/phone-otp/+page.markdoc diff --git a/src/routes/docs/advanced/platform/pro/+page.markdoc b/src/routes/docs/advanced/billing/pro/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/pro/+page.markdoc rename to src/routes/docs/advanced/billing/pro/+page.markdoc diff --git a/src/routes/docs/advanced/platform/refund-policy/+page.markdoc b/src/routes/docs/advanced/billing/refund-policy/+page.markdoc similarity index 97% rename from src/routes/docs/advanced/platform/refund-policy/+page.markdoc rename to src/routes/docs/advanced/billing/refund-policy/+page.markdoc index 18010eadfa8..126ac079c27 100644 --- a/src/routes/docs/advanced/platform/refund-policy/+page.markdoc +++ b/src/routes/docs/advanced/billing/refund-policy/+page.markdoc @@ -44,7 +44,7 @@ The following scenarios do **not** qualify for refunds: - **Incorrect setup or inactivity:** Customer misconfiguration, failure to complete onboarding, or lack of usage - **Expired refund window:** Requests submitted more than 30 days after the transaction date - **Third-party limitations:** Issues caused by third-party tools, plugins, or unsupported integrations -- **Terms of service violations:** Any usage found to be in breach of Appwrite's [Terms](/terms) or [Fair use](/docs/advanced/platform/fair-use-policy) policy +- **Terms of service violations:** Any usage found to be in breach of Appwrite's [Terms](/terms) or [Fair use](/docs/advanced/billing/fair-use-policy) policy # Request process {% #request-process %} diff --git a/src/routes/docs/advanced/platform/scale/+page.markdoc b/src/routes/docs/advanced/billing/scale/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/scale/+page.markdoc rename to src/routes/docs/advanced/billing/scale/+page.markdoc diff --git a/src/routes/docs/advanced/platform/support-sla/+page.markdoc b/src/routes/docs/advanced/billing/support-sla/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/support-sla/+page.markdoc rename to src/routes/docs/advanced/billing/support-sla/+page.markdoc diff --git a/src/routes/docs/advanced/platform/uptime-sla/+page.markdoc b/src/routes/docs/advanced/billing/uptime-sla/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/uptime-sla/+page.markdoc rename to src/routes/docs/advanced/billing/uptime-sla/+page.markdoc diff --git a/src/routes/docs/advanced/integration/+layout.svelte b/src/routes/docs/advanced/integration/+layout.svelte deleted file mode 100644 index ff3459764ea..00000000000 --- a/src/routes/docs/advanced/integration/+layout.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - diff --git a/src/routes/docs/advanced/integration/+page.markdoc b/src/routes/docs/advanced/integration/+page.markdoc deleted file mode 100644 index d08ff00e889..00000000000 --- a/src/routes/docs/advanced/integration/+page.markdoc +++ /dev/null @@ -1,6 +0,0 @@ ---- -layout: article -title: Integration -description: Learn how to use Appwrite Migrations service to move projects from other vendors to Appwrite Cloud or from self-hosting to Cloud and the other way around. ---- -Integration \ No newline at end of file diff --git a/src/routes/docs/advanced/migrations/firebase/+page.markdoc b/src/routes/docs/advanced/migrations/firebase/+page.markdoc index d0eb175d45e..ecfc6322cc5 100644 --- a/src/routes/docs/advanced/migrations/firebase/+page.markdoc +++ b/src/routes/docs/advanced/migrations/firebase/+page.markdoc @@ -56,7 +56,7 @@ To begin migrating to Appwrite, follow these steps. 1. In your Appwrite Console, navigate to **Overview** > **Integrations** > **Platforms**, add the platforms for your Web, Flutter, Android, and iOS apps. Appwrite will reject requests from unknown web, Flutter, and mobile apps to protect from malicious attacks. You app **must be added as a platform** for Appwrite to accept requests. -1. Remember to [add appropriate permissions](/docs/advanced/platform/permissions) to the migrated resources to protect user data and privacy. +1. Remember to [add appropriate permissions](/docs/advanced/security/permissions) to the migrated resources to protect user data and privacy. 1. Migrate functions manually, by [pick a runtime](/docs/products/functions/runtimes) and [learn to develop Appwrite Functions](/docs/products/functions/develop). diff --git a/src/routes/docs/advanced/migrations/nhost/+page.markdoc b/src/routes/docs/advanced/migrations/nhost/+page.markdoc index 66f9a709ddd..9650aabd8a8 100644 --- a/src/routes/docs/advanced/migrations/nhost/+page.markdoc +++ b/src/routes/docs/advanced/migrations/nhost/+page.markdoc @@ -43,7 +43,7 @@ Before migrating to Appwrite make sure you've read the [migration overview](/doc 1. In your Appwrite Console, navigate to **Overview** > **Integrations** > **Platforms**, add the platforms for your Web, Flutter, Android, and iOS apps. Appwrite will reject requests from unknown web, Flutter, and mobile apps to protect from malicious attacks. You app **must be added as a platform** for Appwrite to accept requests. -1. Remember to [add appropriate permissions](/docs/advanced/platform/permissions) to the migrated resources to protect user data and privacy. +1. Remember to [add appropriate permissions](/docs/advanced/security/permissions) to the migrated resources to protect user data and privacy. 1. Migrate functions manually, by [pick a runtime](/docs/products/functions/runtimes) and [learn to develop Appwrite Functions](/docs/products/functions/develop). diff --git a/src/routes/docs/advanced/migrations/supabase/+page.markdoc b/src/routes/docs/advanced/migrations/supabase/+page.markdoc index 8c9fd3628bc..0b715f06cc4 100644 --- a/src/routes/docs/advanced/migrations/supabase/+page.markdoc +++ b/src/routes/docs/advanced/migrations/supabase/+page.markdoc @@ -51,7 +51,7 @@ Before migrating to Appwrite make sure you've read the [migration overview](/doc 1. In your Appwrite Console, navigate to **Overview** > **Integrations** > **Platforms**, add the platforms for your Web, Flutter, Android, and iOS apps. Appwrite will reject requests from unknown web, Flutter, and mobile apps to protect from malicious attacks. You app **must be added as a platform** for Appwrite to accept requests. -1. Remember to [add appropriate permissions](/docs/advanced/platform/permissions) to the migrated resources to protect user data and privacy. +1. Remember to [add appropriate permissions](/docs/advanced/security/permissions) to the migrated resources to protect user data and privacy. 1. Migrate functions manually, by [pick a runtime](/docs/products/functions/runtimes) and [learn to develop Appwrite Functions](/docs/products/functions/develop). diff --git a/src/routes/docs/advanced/platform/+layout.svelte b/src/routes/docs/advanced/platform/+layout.svelte deleted file mode 100644 index 219c63c770e..00000000000 --- a/src/routes/docs/advanced/platform/+layout.svelte +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - diff --git a/src/routes/docs/advanced/platform/+page.markdoc b/src/routes/docs/advanced/platform/+page.markdoc deleted file mode 100644 index d85400548e1..00000000000 --- a/src/routes/docs/advanced/platform/+page.markdoc +++ /dev/null @@ -1,123 +0,0 @@ ---- -layout: article -title: Platform -description: Appwrite is a development platform designed to adapt to your unique use cases. It provides features that help you maintain and scale your application. ---- - -Appwrite is a development platform designed to adapt your unique use cases. -Appwrite provides features that help you maintain, scale, and integrate Appwrite with other platforms. - -# Integration {% #integration %} - -Appwrite is designed to integrate with both frontend and backend apps. -Learn about advanced integrations and API response codes. - -{% cards %} -{% cards_item href="/docs/advanced/platform/events" title="Events" %} -Appwrite allows you to react to events that occur on the platform. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/webhooks" title="Webhooks" %} -Use webhooks to update backend integrations about Appwrite events. -{% /cards_item %} - -{% cards_item - href="/docs/advanced/platform/response-codes" - title="Response codes" %} -Learn about response codes and errors returned by Appwrite APIs. -{% /cards_item %} -{% /cards %} - -# Access control {% #access-control %} - -Appwrite is secure by default and provides tools for you to manage -access control and prevent abuse. - -{% cards %} -{% cards_item - href="/docs/advanced/platform/permissions" - title="Permissions" %} -Control which users can access which resources. -{% /cards_item %} - -{% cards_item - href="/docs/advanced/platform/rate-limits" - title="Rate limits" %} -Appwrite has rate limits on some endpoints to prevent abuse. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/api-keys" title="API keys" %} -Create and manage API keys used by Server SDKs. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/dev-keys" title="Dev keys" %} -Create and manage dev keys used by Client SDKs in dev environments. -{% /cards_item %} -{% /cards %} - -# Plans {% #plans %} - -Learn which plan best suits your organization and how to manage billing. - -{% cards %} -{% cards_item href="/docs/advanced/platform/billing" title="Billing" %} -Learn to manage your billing information. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/free" title="Free" %} -Learn about Appwrite Free plan. Free plan for hobby projects and learners. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/pro" title="Pro" %} -Learn about Appwrite Pro, for growing organizations that need to scale. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/scale" title="Scale" %} -Coming soon. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/enterprise" title="Enterprise" %} -Learn about Appwrite Enterprise, for large organizations with advanced needs. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/oss" title="Open source" %} -Appwrite provides special plans for open source projects. -{% /cards_item %} -{% /cards %} - -# Configuration {% #configuration %} - -Configure custom domains and customize communication templates. - -{% cards %} -{% cards_item - href="/docs/advanced/platform/custom-domains" - title="Custom domains" %} -Add a custom domain for your Appwrite APIs. -{% /cards_item %} - -{% cards_item - href="/docs/advanced/platform/message-templates" - title="Message templates" %} -Create custom branding and messages when you communicate with users. -{% /cards_item %} -{% /cards %} - -# Add Ons {% #add-ons %} - -Learn about additional features and functionalities that Appwrite offers. - -{% cards %} -{% cards_item href="/docs/advanced/platform/compute" title="Compute" %} -CPU and memory for Functions and Sites, including build and runtime specs. -{% /cards_item %} -{% cards_item href="/docs/advanced/platform/phone-otp" title="Phone OTP" %} -Learn how Appwrite handles SMS-based OTP authentication. -{% /cards_item %} -{% cards_item href="/docs/advanced/platform/image-transformations" title="Image Transformations" %} -Learn how to transform images dynamically with Appwrite. -{% /cards_item %} -{% cards_item href="/docs/advanced/platform/database-reads-and-writes" title="Database Reads and Writes" %} -Learn how Appwrite handles database reads and writes. -{% /cards_item %} -{% /cards %} \ No newline at end of file diff --git a/src/routes/docs/advanced/security/+layout.svelte b/src/routes/docs/advanced/security/+layout.svelte index 7caeaa87a58..77154195a84 100644 --- a/src/routes/docs/advanced/security/+layout.svelte +++ b/src/routes/docs/advanced/security/+layout.svelte @@ -82,6 +82,36 @@ href: '/docs/advanced/security/abuse-protection' } ] + }, + { + label: 'Access control', + items: [ + { + label: 'Permissions', + href: '/docs/advanced/security/permissions' + }, + { + label: 'Rate limits', + href: '/docs/advanced/security/rate-limits' + }, + { + label: 'API keys', + href: '/docs/advanced/security/api-keys' + }, + { + label: 'Dev keys', + href: '/docs/advanced/security/dev-keys' + } + ] + }, + { + label: 'Configuration', + items: [ + { + label: 'Environment variables', + href: '/docs/advanced/security/environment-variables' + } + ] } ]; diff --git a/src/routes/docs/advanced/security/+page.markdoc b/src/routes/docs/advanced/security/+page.markdoc index f3a43824ee9..57586ef4c6f 100644 --- a/src/routes/docs/advanced/security/+page.markdoc +++ b/src/routes/docs/advanced/security/+page.markdoc @@ -9,7 +9,7 @@ Appwrite is compliant with [GDPR](/docs/advanced/security/gdpr), [CCPA](/docs/ad [HIPAA](/docs/advanced/security/hipaa), and [SOC 2](/docs/advanced/security/soc2). Appwrite also employs [enhanced password protection and encryption](/docs/products/auth/security), [rate limits](/docs/advanced/security/abuse-protection), -[robust permission systems](/docs/advanced/platform/permissions), and [HTTPS/TLS](/docs/advanced/security/tls) to protect you and your users' data. +[robust permission systems](/docs/advanced/security/permissions), and [HTTPS/TLS](/docs/advanced/security/tls) to protect you and your users' data. # Compliance {% #compliance %} @@ -54,12 +54,17 @@ Appwrite encrypts sensitive data and files in Appwrite Databases and Storage. {% /cards_item %} +{% cards_item href="/docs/advanced/security/mfa" title="Multi-factor authentication" %} +Add a second layer of protection by requiring +users to verify their identity with multiple factors. +{% /cards_item %} + {% cards_item href="/docs/advanced/security/https" title="HTTPS" %} Appwrite Cloud enforces HTTPS on all endpoints to prevent on-path attacks like packet sniffing. {% /cards_item %} -{% cards_item href="/docs/advanced/security/https" title="TLS" %} +{% cards_item href="/docs/advanced/security/tls" title="TLS" %} Appwrite assigns TLS certificates on all Appwrite and user provided domains connected to Appwrite. {% /cards_item %} @@ -86,6 +91,39 @@ like DoS and brute-force attacks. {% /cards %} +# Access control {% #access-control %} + +Appwrite is secure by default and provides tools for you to manage +access control and prevent abuse. + +{% cards %} +{% cards_item href="/docs/advanced/security/permissions" title="Permissions" %} +Control which users can access which resources. +{% /cards_item %} + +{% cards_item href="/docs/advanced/security/rate-limits" title="Rate limits" %} +Appwrite has rate limits on some endpoints to prevent abuse. +{% /cards_item %} + +{% cards_item href="/docs/advanced/security/api-keys" title="API keys" %} +Create and manage API keys used by Server SDKs. +{% /cards_item %} + +{% cards_item href="/docs/advanced/security/dev-keys" title="Dev keys" %} +Create and manage dev keys used by Client SDKs in dev environments. +{% /cards_item %} +{% /cards %} + +# Configuration {% #configuration %} + +Pass constants and secrets to your Appwrite resources. + +{% cards %} +{% cards_item href="/docs/advanced/security/environment-variables" title="Environment variables" %} +Use project, function, and site environment variables to pass constants and secrets to your Functions and Sites. +{% /cards_item %} +{% /cards %} + # Reporting vulnerabilities {% #reporting-vulnerabilities %} If you discover security vulnerabilities, please contact us at security@appwrite.io. Please avoid **posting a public issue** on GitHub or elsewhere online to prevent malicious actors diff --git a/src/routes/docs/advanced/security/abuse-protection/+page.markdoc b/src/routes/docs/advanced/security/abuse-protection/+page.markdoc index d44dc44992a..95063ed3874 100644 --- a/src/routes/docs/advanced/security/abuse-protection/+page.markdoc +++ b/src/routes/docs/advanced/security/abuse-protection/+page.markdoc @@ -14,7 +14,7 @@ Rate limits limit the number of requests a user or IP can make against an API wi Rate limits help protect against brute force attacks against authentication endpoints and other forms of API abuse like [denial of service attacks](https://en.wikipedia.org/wiki/Denial-of-service_attack). -{% arrow_link href="/docs/advanced/platform/rate-limits" %} +{% arrow_link href="/docs/advanced/security/rate-limits" %} Learn more about rate limits {% /arrow_link %} diff --git a/src/routes/docs/advanced/platform/api-keys/+page.markdoc b/src/routes/docs/advanced/security/api-keys/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/platform/api-keys/+page.markdoc rename to src/routes/docs/advanced/security/api-keys/+page.markdoc index 544159552ef..f3ff9924f88 100644 --- a/src/routes/docs/advanced/platform/api-keys/+page.markdoc +++ b/src/routes/docs/advanced/security/api-keys/+page.markdoc @@ -14,7 +14,7 @@ API keys should be treated as a secret. Never share the API key and keep API key # API keys vs Dev keys {% #api-keys-vs-dev-keys %} -API keys and [Dev keys](/docs/advanced/platform/dev-keys) are not the same and cannot be used interchangeably. +API keys and [Dev keys](/docs/advanced/security/dev-keys) are not the same and cannot be used interchangeably. API keys permit access to Appwrite services in production environments, with access controlled through scopes to ensure secure and controlled server-side operations. Dev keys, conversely, are specifically designed to help you avoid abuse limits and CORS errors in test and development environments. diff --git a/src/routes/docs/advanced/security/audit-logs/+page.markdoc b/src/routes/docs/advanced/security/audit-logs/+page.markdoc index 342758fddc4..b35cc10c2cb 100644 --- a/src/routes/docs/advanced/security/audit-logs/+page.markdoc +++ b/src/routes/docs/advanced/security/audit-logs/+page.markdoc @@ -36,7 +36,7 @@ Each entry describes an event. - Name of the user that performed the event. --- - Event -- The name of the [event](/docs/advanced/platform/events). +- The name of the [event](/docs/advanced/api-integration/events). --- - Location - The physical of the user when they performed the action. diff --git a/src/routes/docs/advanced/platform/dev-keys/+page.markdoc b/src/routes/docs/advanced/security/dev-keys/+page.markdoc similarity index 93% rename from src/routes/docs/advanced/platform/dev-keys/+page.markdoc rename to src/routes/docs/advanced/security/dev-keys/+page.markdoc index b19590abb3b..bb3ee0e89f4 100644 --- a/src/routes/docs/advanced/platform/dev-keys/+page.markdoc +++ b/src/routes/docs/advanced/security/dev-keys/+page.markdoc @@ -4,6 +4,10 @@ title: Dev keys description: Bypass Appwrite rate limits and CORS errors in your development environment with Appwrite Dev keys. --- +{% info title="Deprecation notice" %} +Dev keys are going to be deprecated soon. We recommend planning your migration away from dev keys ahead of time. +{% /info %} + Dev keys are secrets used by Appwrite [Client SDKs](/docs/sdks#client) to avoid abuse limits in testing. They are meant to be used specifically in development environments, where they hold several developer experience-related benefits: - Appwrite rate limits and CORS errors are bypassed @@ -17,7 +21,7 @@ Dev keys should never be used in production environments, only in development en # Dev keys vs API keys {% #dev-keys-vs-api-keys %} -Dev keys and [API keys](/docs/advanced/platform/api-keys) are not the same and cannot be used interchangeably. +Dev keys and [API keys](/docs/advanced/security/api-keys) are not the same and cannot be used interchangeably. Dev keys are specifically designed to help you avoid abuse limits and CORS errors in test environments, making them ideal for development and testing workflows. API keys, on the other hand, permit usage of Appwrite services in production environments with fine-grained scope control. diff --git a/src/routes/docs/advanced/platform/environment-variables/+page.markdoc b/src/routes/docs/advanced/security/environment-variables/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/platform/environment-variables/+page.markdoc rename to src/routes/docs/advanced/security/environment-variables/+page.markdoc index c61134bc0cb..55542191a91 100644 --- a/src/routes/docs/advanced/platform/environment-variables/+page.markdoc +++ b/src/routes/docs/advanced/security/environment-variables/+page.markdoc @@ -52,7 +52,7 @@ You can create and manage project variables from the Appwrite Console. The Conso # Manage with a Server SDK {% #server-sdks %} -You can also manage project variables programmatically using a [Server SDK](/docs/sdks#server). Each call requires an [API key](/docs/advanced/platform/api-keys) with the `project.write` scope to create, update, or delete variables, or the `project.read` scope to list and read them. +You can also manage project variables programmatically using a [Server SDK](/docs/sdks#server). Each call requires an [API key](/docs/advanced/security/api-keys) with the `project.write` scope to create, update, or delete variables, or the `project.read` scope to list and read them. ## Create a variable {% #create-variable %} diff --git a/src/routes/docs/advanced/security/https/+page.markdoc b/src/routes/docs/advanced/security/https/+page.markdoc index e33da7b7669..44602ebcd37 100644 --- a/src/routes/docs/advanced/security/https/+page.markdoc +++ b/src/routes/docs/advanced/security/https/+page.markdoc @@ -25,7 +25,7 @@ man-in-the-middle attacks such as protocol downgrade attacks and cookie hijackin By enforcing HTTPS, Appwrite Cloud's endpoint will always be served over a secure connection, which helps protect users' data and privacy. # Custom domains {% #custom-domains %} -You can add a [custom domain](/docs/advanced/platform/custom-domains) to your Appwrite project so you can access Appwrite API endpoints +You can add a [custom domain](/docs/products/network/custom-domains) to your Appwrite project so you can access Appwrite API endpoints on your own domain. Appwrite will [generate TLS certificates](/docs/advanced/security/tls) for your domain and enforce HTTPS communication. # Function domains {% #function-domains %} diff --git a/src/routes/docs/advanced/platform/permissions/+page.markdoc b/src/routes/docs/advanced/security/permissions/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/platform/permissions/+page.markdoc rename to src/routes/docs/advanced/security/permissions/+page.markdoc index e0b2d1c12f1..c6b289345ab 100644 --- a/src/routes/docs/advanced/platform/permissions/+page.markdoc +++ b/src/routes/docs/advanced/security/permissions/+page.markdoc @@ -26,7 +26,7 @@ If you create a resource using a Server SDK or the Appwrite Console without expl # Server integration {% #server-integration %} -Server integrations can be used for increased flexibility. When using a Server SDK in combination with the proper [API key scopes](/docs/advanced/platform/api-keys#scopes), you can have any type of access to any of your project resources regardless of their permissions. +Server integrations can be used for increased flexibility. When using a Server SDK in combination with the proper [API key scopes](/docs/advanced/security/api-keys#scopes), you can have any type of access to any of your project resources regardless of their permissions. Using the server integration flexibility, you can change resource permissions, share resources between different users and teams, or edit and delete them without any limitations. diff --git a/src/routes/docs/advanced/platform/rate-limits/+page.markdoc b/src/routes/docs/advanced/security/rate-limits/+page.markdoc similarity index 98% rename from src/routes/docs/advanced/platform/rate-limits/+page.markdoc rename to src/routes/docs/advanced/security/rate-limits/+page.markdoc index 256e0529dad..337fc15c82f 100644 --- a/src/routes/docs/advanced/platform/rate-limits/+page.markdoc +++ b/src/routes/docs/advanced/security/rate-limits/+page.markdoc @@ -52,7 +52,7 @@ X-RateLimit-Reset: 1377013266 # Dev keys {% #dev-keys %} -Rate limits are necessary to protect your apps and users from abuse; however, they can sometimes add unwanted friction when a developer is trying to repeatedly consume certain Appwrite APIs to test their application in a short period. [Dev keys](/docs/advanced/platform/dev-keys) are a type of secret used by client apps to bypass these rate limits in development environments. +Rate limits are necessary to protect your apps and users from abuse; however, they can sometimes add unwanted friction when a developer is trying to repeatedly consume certain Appwrite APIs to test their application in a short period. [Dev keys](/docs/advanced/security/dev-keys) are a type of secret used by client apps to bypass these rate limits in development environments. To use dev keys, client apps add a header `X-Appwrite-Dev-Key` containing the secret to all HTTP requests sent to the Appwrite API. Appwrite recognizes this header, verifies the secret, and if valid, allows the request to bypass the rate limit. diff --git a/src/routes/docs/advanced/security/tls/+page.markdoc b/src/routes/docs/advanced/security/tls/+page.markdoc index b0c21bdee10..31eeee2347a 100644 --- a/src/routes/docs/advanced/security/tls/+page.markdoc +++ b/src/routes/docs/advanced/security/tls/+page.markdoc @@ -11,7 +11,7 @@ Appwrite generates TLS certificates to ensure your API traffic is appropriately TLS certificates are generated for all of the following. - Appwrite products and endpoints, like Databases, Storage, Authentication, Functions, Messaging, and all other endpoints. -- [Custom domains](/docs/advanced/platform/custom-domains) that you configure for your Appwrite projects. +- [Custom domains](/docs/products/network/custom-domains) that you configure for your Appwrite projects. - [Domains for Appwrite Functions](/docs/products/functions/domains), generated or user provided. - [Domains for Appwrite Sites](/docs/products/sites/domains), generated or user provided. diff --git a/src/routes/docs/advanced/self-hosting/production/debugging/+page.markdoc b/src/routes/docs/advanced/self-hosting/production/debugging/+page.markdoc index e846a71384c..6f6360ca299 100644 --- a/src/routes/docs/advanced/self-hosting/production/debugging/+page.markdoc +++ b/src/routes/docs/advanced/self-hosting/production/debugging/+page.markdoc @@ -34,7 +34,7 @@ docker logs [CONTAINER-ID] Appwrite uses conventional HTTP response codes to indicate the success or failure of an API request. In general: Codes in the 2xx range indicate success. Codes in the 4xx range indicate an error that failed given the information provided (e.g., a required parameter was omitted, invalid input, etc.). Codes in the 5xx range indicate an error with the Appwrite server, but these are rare. -{% arrow_link href="/docs/advanced/platform/response-codes" %} +{% arrow_link href="/docs/advanced/api-integration/response-codes" %} Learn more about Appwrite status codes {% /arrow_link %} diff --git a/src/routes/docs/advanced/self-hosting/production/rate-limits/+page.markdoc b/src/routes/docs/advanced/self-hosting/production/rate-limits/+page.markdoc index 97fc1aa4358..9a33e9c3054 100644 --- a/src/routes/docs/advanced/self-hosting/production/rate-limits/+page.markdoc +++ b/src/routes/docs/advanced/self-hosting/production/rate-limits/+page.markdoc @@ -15,7 +15,7 @@ Rate limits in self-hosted Appwrite apply differently depending on how you're ac - **Client SDKs**: Rate limits apply to all requests from client applications - **Server SDKs with API keys**: Rate limits do not apply when using API keys -{% arrow_link href="/docs/advanced/platform/rate-limits" %} +{% arrow_link href="/docs/advanced/security/rate-limits" %} Learn more about how rate limits work {% /arrow_link %} diff --git a/src/routes/docs/apis/realtime/+page.markdoc b/src/routes/docs/apis/realtime/+page.markdoc index 00539e3010f..cbd5b9218f7 100644 --- a/src/routes/docs/apis/realtime/+page.markdoc +++ b/src/routes/docs/apis/realtime/+page.markdoc @@ -116,10 +116,10 @@ To subscribe to updates from different Appwrite resources, you need to specify o If you subscribe to a channel, you will receive callbacks for a variety of events related to the channel. The events column in the callback can be used to filter and respond to specific events in a channel. -[View a list of all available events](/docs/advanced/platform/events). +[View a list of all available events](/docs/advanced/api-integration/events). {% info title="Permissions" %} -All subscriptions are secured by the [permissions system](/docs/advanced/platform/permissions) offered by Appwrite, meaning a user will only receive updates to resources they have permission to access. +All subscriptions are secured by the [permissions system](/docs/advanced/security/permissions) offered by Appwrite, meaning a user will only receive updates to resources they have permission to access. Using `Role.any()` on read permissions will allow any client to receive updates. {% /info %} diff --git a/src/routes/docs/apis/realtime/authentication/+page.markdoc b/src/routes/docs/apis/realtime/authentication/+page.markdoc index 15bf09155ad..7e1fcbe0506 100644 --- a/src/routes/docs/apis/realtime/authentication/+page.markdoc +++ b/src/routes/docs/apis/realtime/authentication/+page.markdoc @@ -9,7 +9,7 @@ Realtime authenticates using an existing user session. If you authenticate **aft More information and examples of authenticating users can be found in the dedicated [authentication docs](/docs/products/auth). {% info title="Permissions" %} -All subscriptions are secured by the [permissions system](/docs/advanced/platform/permissions) offered by Appwrite, meaning a user will only receive updates to resources they have permission to access. +All subscriptions are secured by the [permissions system](/docs/advanced/security/permissions) offered by Appwrite, meaning a user will only receive updates to resources they have permission to access. Using `Role.any()` on read permissions will allow any client to receive updates. {% /info %} diff --git a/src/routes/docs/apis/realtime/payload/+page.markdoc b/src/routes/docs/apis/realtime/payload/+page.markdoc index 37489cdc7b1..b6a70760351 100644 --- a/src/routes/docs/apis/realtime/payload/+page.markdoc +++ b/src/routes/docs/apis/realtime/payload/+page.markdoc @@ -17,7 +17,7 @@ The payload from the subscription will contain the following properties: --- * events * string[] -* The [Appwrite events](/docs/advanced/platform/events) that triggered this update. +* The [Appwrite events](/docs/advanced/api-integration/events) that triggered this update. --- * channels * string[] diff --git a/src/routes/docs/apis/realtime/presences/+page.markdoc b/src/routes/docs/apis/realtime/presences/+page.markdoc index 1b5153a64d9..94915ef15ed 100644 --- a/src/routes/docs/apis/realtime/presences/+page.markdoc +++ b/src/routes/docs/apis/realtime/presences/+page.markdoc @@ -115,7 +115,7 @@ The SDK remembers the latest payload and re-sends it after a reconnect, so a bri # Upsert a presence {% #upsert-a-presence %} -`upsert` creates a presence or updates the existing record with the same `presenceId`. Call it on every page navigation, focus change, or heartbeat without worrying about duplicates. From a client session, `userId` is inferred from the signed-in user; from a server SDK with an API key, pass `userId` explicitly. Server SDKs need an [API key](/docs/advanced/platform/api-keys) with the `presences.write` scope. +`upsert` creates a presence or updates the existing record with the same `presenceId`. Call it on every page navigation, focus change, or heartbeat without worrying about duplicates. From a client session, `userId` is inferred from the signed-in user; from a server SDK with an API key, pass `userId` explicitly. Server SDKs need an [API key](/docs/advanced/security/api-keys) with the `presences.write` scope. {% multicode %} ```client-web @@ -1578,7 +1578,7 @@ async fn main() -> Result<(), Box> { # Subscribe to presence updates {% #subscribe-to-presence-updates %} -Presence is most useful when other clients can react to it live. Use the `Channel.presences()` helper to subscribe to the global presences channel, or `Channel.presence('')` to follow a single record. All Realtime subscriptions are gated by the [permissions system](/docs/advanced/platform/permissions), so a client will only receive updates for presences it has permission to read. +Presence is most useful when other clients can react to it live. Use the `Channel.presences()` helper to subscribe to the global presences channel, or `Channel.presence('')` to follow a single record. All Realtime subscriptions are gated by the [permissions system](/docs/advanced/security/permissions), so a client will only receive updates for presences it has permission to read. {% multicode %} ```client-web @@ -1781,7 +1781,7 @@ To remove a presence immediately, for example on sign out or when the user close # Permissions and scopes {% #permissions-and-scopes %} -Presences use the standard Appwrite [permissions system](/docs/advanced/platform/permissions). Set read permissions on a presence to control who can subscribe to it: +Presences use the standard Appwrite [permissions system](/docs/advanced/security/permissions). Set read permissions on a presence to control who can subscribe to it: - `Role.any()` makes the presence visible to anyone, including unauthenticated visitors. - `Role.users()` restricts visibility to signed-in users. diff --git a/src/routes/docs/apis/rest/+page.markdoc b/src/routes/docs/apis/rest/+page.markdoc index 89e38712406..bf5c8d0d2a3 100644 --- a/src/routes/docs/apis/rest/+page.markdoc +++ b/src/routes/docs/apis/rest/+page.markdoc @@ -113,7 +113,7 @@ X-Appwrite-Project: Server integrations use API keys to authenticate and are typically used for backend applications. -Server APIs are authenticated with API keys instead of account sessions. Simply pass an [API key](/docs/advanced/platform/api-keys) in the `X-Appwrite-key: [API-KEY]` header with the appropriate scopes. +Server APIs are authenticated with API keys instead of account sessions. Simply pass an [API key](/docs/advanced/security/api-keys) in the `X-Appwrite-key: [API-KEY]` header with the appropriate scopes. ```json GET /v1/tablesdb/{databaseId}/tables/{tableId}/rows HTTP/1.1 @@ -464,7 +464,7 @@ In these cases, `column` is empty and `values` is an array of queries. Appwrite's REST APIs are protected by the same rate limit policies, just like when using an SDK. Each API has a different rate limit, which is documented in the References section of each service in the Appwrite documentation. -[Learn more about Rate Limits](/docs/advanced/platform/rate-limits). +[Learn more about Rate Limits](/docs/advanced/security/rate-limits). # Specifications {% #specifications %} diff --git a/src/routes/docs/products/auth/+layout.svelte b/src/routes/docs/products/auth/+layout.svelte index 2e8370ca5f3..eb515ad35bb 100644 --- a/src/routes/docs/products/auth/+layout.svelte +++ b/src/routes/docs/products/auth/+layout.svelte @@ -37,6 +37,10 @@ label: 'Teams', href: '/docs/products/auth/teams' }, + { + label: 'Roles', + href: '/docs/products/auth/roles' + }, { label: 'Impersonation', href: '/docs/products/auth/impersonation', @@ -59,6 +63,10 @@ href: '/docs/products/auth/email-policies', new: isNewUntil('30 June 2026') }, + { + label: 'Message templates', + href: '/docs/products/auth/message-templates' + }, { label: 'Tokens', href: '/docs/products/auth/tokens' diff --git a/src/routes/docs/products/auth/accounts/+page.markdoc b/src/routes/docs/products/auth/accounts/+page.markdoc index 4964d1240fb..93e231c6d99 100644 --- a/src/routes/docs/products/auth/accounts/+page.markdoc +++ b/src/routes/docs/products/auth/accounts/+page.markdoc @@ -33,7 +33,7 @@ individual users using the `Role.user(, )` role. | Unverified user | `Role.user(, 'unverified')` | -{% arrow_link href="/docs/advanced/platform/permissions" %} +{% arrow_link href="/docs/advanced/security/permissions" %} Learn more about permissions {% /arrow_link %} diff --git a/src/routes/docs/products/auth/jwt/+page.markdoc b/src/routes/docs/products/auth/jwt/+page.markdoc index 87fb0e8d12d..5dee26b3549 100644 --- a/src/routes/docs/products/auth/jwt/+page.markdoc +++ b/src/routes/docs/products/auth/jwt/+page.markdoc @@ -10,7 +10,7 @@ If you are already authenticated on your client-side app and need your backend a # Proof of Identity {% #proof-of-identity %} -Before making requests to your backend APIs, your client application needs to first create a session **directly with Appwrite** using the account service. This session will act like an ID card for the user and can be used to access resources in Appwrite. The client will **only receive information accessible to the user** based on the resources' [permissions](/docs/advanced/platform/permissions). +Before making requests to your backend APIs, your client application needs to first create a session **directly with Appwrite** using the account service. This session will act like an ID card for the user and can be used to access resources in Appwrite. The client will **only receive information accessible to the user** based on the resources' [permissions](/docs/advanced/security/permissions). When you build backend APIs to extend Appwrite's functionality, these APIs should still **respect access permissions** to keep user data secure. Appwrite's backend SDKs allow you to securely act on behalf of a user with the same permissions by using JWT authentication. @@ -173,7 +173,7 @@ var client = new Client() JWT auth is useful when you need your backend app's Server SDK to be restricted by the same set of permissions. -If your backend app's Server SDK is using an [API key](/docs/advanced/platform/api-keys), it will fetch **all resources** regardless of permissions. This means the Server SDK might fetch files and rows your user should not be able to see, which is not helpful when you need to act on behalf of a user. +If your backend app's Server SDK is using an [API key](/docs/advanced/security/api-keys), it will fetch **all resources** regardless of permissions. This means the Server SDK might fetch files and rows your user should not be able to see, which is not helpful when you need to act on behalf of a user. If your backend app's Server SDK is using a **JWT**, it will only fetch resources your user has permissions to access. diff --git a/src/routes/docs/products/auth/labels/+page.markdoc b/src/routes/docs/products/auth/labels/+page.markdoc index 1a209b272a1..25832378b2b 100644 --- a/src/routes/docs/products/auth/labels/+page.markdoc +++ b/src/routes/docs/products/auth/labels/+page.markdoc @@ -206,6 +206,6 @@ This would correspond with the permissions below. | Delete | `Permissions.delete(Role.label('subscriber'))` | | Create | `Permissions.create(Role.label('subscriber'))` | -{% arrow_link href="/docs/advanced/platform/permissions" %} +{% arrow_link href="/docs/advanced/security/permissions" %} Learn more about permissions {% /arrow_link %} \ No newline at end of file diff --git a/src/routes/docs/advanced/platform/message-templates/+page.markdoc b/src/routes/docs/products/auth/message-templates/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/platform/message-templates/+page.markdoc rename to src/routes/docs/products/auth/message-templates/+page.markdoc index aca728a99a1..f4aa1f30951 100644 --- a/src/routes/docs/advanced/platform/message-templates/+page.markdoc +++ b/src/routes/docs/products/auth/message-templates/+page.markdoc @@ -62,7 +62,7 @@ Variables can be used in email templates to dynamically construct unique emails | `{{user}}` | The name of the user receiving the email. This variable is not available in the Magic URL template, as there might not be a user yet. | | `{{redirect}}` | The URL for the user to complete the email template's action. | -## Email template syntax {% #email-template-examples %} +## Email template examples {% #email-template-examples %} Here's an example of using these variables in a template. diff --git a/src/routes/docs/products/auth/phone-sms/+page.markdoc b/src/routes/docs/products/auth/phone-sms/+page.markdoc index 16661555d05..6681eb38dd3 100644 --- a/src/routes/docs/products/auth/phone-sms/+page.markdoc +++ b/src/routes/docs/products/auth/phone-sms/+page.markdoc @@ -5,7 +5,7 @@ description: Enhance security with SMS and phone authentication in Appwrite. Add --- {% info title="Note" %} -OTPs are billed per message, with rates varying by country. See the [phone OTP rates](/docs/advanced/platform/phone-otp#rates) for more information. +OTPs are billed per message, with rates varying by country. See the [phone OTP rates](/docs/advanced/billing/phone-otp#rates) for more information. {% /info %} Phone authentication lets users create accounts using their phone numbers and log in through SMS messages. diff --git a/src/routes/docs/products/auth/presences/+page.markdoc b/src/routes/docs/products/auth/presences/+page.markdoc index 63ef05d2f6e..e41639c9ab8 100644 --- a/src/routes/docs/products/auth/presences/+page.markdoc +++ b/src/routes/docs/products/auth/presences/+page.markdoc @@ -6,7 +6,7 @@ description: Track which signed-in users are active right now and broadcast thei Authentication tells you **who a user is**. Presences tell you **whether they are around right now**. The Appwrite **Presences API** records a live status for each signed-in user and broadcasts every change over [Realtime](/docs/apis/realtime), so your app can render online indicators, "viewing this page" cues, typing signals, and collaboration banners without writing any socket plumbing. -A presence is a short-lived record attached to a user. It carries a `userId`, a `status` string, an optional `metadata` JSON object for richer context, and an `expiresAt` timestamp that controls automatic cleanup. Presences are written by either the user's own session or a server SDK, and read by any client with the right [permissions](/docs/advanced/platform/permissions). +A presence is a short-lived record attached to a user. It carries a `userId`, a `status` string, an optional `metadata` JSON object for richer context, and an `expiresAt` timestamp that controls automatic cleanup. Presences are written by either the user's own session or a server SDK, and read by any client with the right [permissions](/docs/advanced/security/permissions). # Set the user's presence {% #set-the-users-presence %} @@ -125,7 +125,7 @@ There is no fixed heartbeat interval enforced by the server, so pick whichever c # Show other users' presence {% #show-other-users-presence %} -List the presences the current user can read to paint the initial "online now" view, a list of viewers on a page, or a typing dot in a chat. The list call honors the same [permissions](/docs/advanced/platform/permissions) you set on each record, so each client only sees the statuses it is allowed to render. +List the presences the current user can read to paint the initial "online now" view, a list of viewers on a page, or a typing dot in a chat. The list call honors the same [permissions](/docs/advanced/security/permissions) you set on each record, so each client only sees the statuses it is allowed to render. {% multicode %} ```client-web @@ -313,7 +313,7 @@ If a user closes the browser tab or loses connection without signing out, the re # Scoping who can see a presence {% #scoping-who-can-see-a-presence %} -Presences use the standard Appwrite [permissions system](/docs/advanced/platform/permissions). Set read permissions on each record to match how your app already groups users: +Presences use the standard Appwrite [permissions system](/docs/advanced/security/permissions). Set read permissions on each record to match how your app already groups users: - `Role.users()` for any signed-in user, useful for a global "X users online" counter. - `Role.team('')` for collaboration features that should only show statuses to teammates. @@ -407,4 +407,4 @@ If you do not pass a `permissions` array when upserting a presence, Appwrite def - [Realtime: Presences](/docs/apis/realtime/presences). The full concept reference, including channel patterns, expiry behaviour, and server-side usage. - [Realtime channels](/docs/apis/realtime/channels). See how `presences` fits alongside `account`, `teams`, and `rows`. -- [Permissions](/docs/advanced/platform/permissions). Refresher on how `Role.team()` and `Role.user()` work. +- [Permissions](/docs/advanced/security/permissions). Refresher on how `Role.team()` and `Role.user()` work. diff --git a/src/routes/docs/advanced/platform/roles/+page.markdoc b/src/routes/docs/products/auth/roles/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/roles/+page.markdoc rename to src/routes/docs/products/auth/roles/+page.markdoc diff --git a/src/routes/docs/products/auth/server-side-rendering/+page.markdoc b/src/routes/docs/products/auth/server-side-rendering/+page.markdoc index a77e9bec0e7..2cf2f21fbeb 100644 --- a/src/routes/docs/products/auth/server-side-rendering/+page.markdoc +++ b/src/routes/docs/products/auth/server-side-rendering/+page.markdoc @@ -46,7 +46,7 @@ Admin clients should only be used if you need to perform admin actions that bypa or [unauthenticated requests that bypass rate limits](#rate-limits). {% /info %} -To initialize the admin client, we'll need to first [generate an API key](/docs/advanced/platform/api-keys#create-api-key). +To initialize the admin client, we'll need to first [generate an API key](/docs/advanced/security/api-keys#create-api-key). The API key should have the following scope in order to perform authentication: | Category {% width=120 %} | Required scopes | Purpose | @@ -94,7 +94,7 @@ let admin_client = Client::new() ``` {% /multicode %} -It is important to use an API key, as this will allow your server requests to bypass [rate limits](/docs/advanced/platform/rate-limits). If you don't use an API key, your server will be rate limited as if it were a client from a single IP address. +It is important to use an API key, as this will allow your server requests to bypass [rate limits](/docs/advanced/security/rate-limits). If you don't use an API key, your server will be rate limited as if it were a client from a single IP address. ## Session client {% #session-client %} @@ -103,7 +103,7 @@ It will be initialized with the session, usually stored within a cookie. You should create a new client for each request and **never** share the client between requests. -Use `a_session_` as the [cookie name](/docs/apis/rest#client-integration) and a [custom domain](/docs/advanced/platform/custom-domains) for your Appwrite endpoint if you want the session to work client-side as well. +Use `a_session_` as the [cookie name](/docs/apis/rest#client-integration) and a [custom domain](/docs/products/network/custom-domains) for your Appwrite endpoint if you want the session to work client-side as well. {% multicode %} ```server-nodejs @@ -406,7 +406,7 @@ let user = account.get().await?; {% /multicode %} # Rate limits {% #rate-limits %} -Unauthenticated requests are subject to [rate limits](/docs/advanced/platform/rate-limits). +Unauthenticated requests are subject to [rate limits](/docs/advanced/security/rate-limits). Normally, rate limits are applied by an abuse key, which is usually a combination of IP and another factor like user ID. When you make unauthenticated requests from your server, however, all requests originate from the same IP and no user ID is provided. This means that all unauthenticated requests from your server will be **subject to the same rate limits**. diff --git a/src/routes/docs/products/auth/team-invites/+page.markdoc b/src/routes/docs/products/auth/team-invites/+page.markdoc index c16614d1f34..1da1e5b5a8a 100644 --- a/src/routes/docs/products/auth/team-invites/+page.markdoc +++ b/src/routes/docs/products/auth/team-invites/+page.markdoc @@ -792,7 +792,7 @@ val isAdmin = membership?.roles?.contains("admin") ?: false ``` {% /multicode %} -See how to grant row and file access to team roles in the [permissions](/docs/advanced/platform/permissions#example-2-team-roles) guide. +See how to grant row and file access to team roles in the [permissions](/docs/advanced/security/permissions#example-2-team-roles) guide. {% arrow_link href="/docs/products/auth/teams" %} Learn more about team management diff --git a/src/routes/docs/products/auth/teams/+page.markdoc b/src/routes/docs/products/auth/teams/+page.markdoc index 7df0d562003..3303c653e8a 100644 --- a/src/routes/docs/products/auth/teams/+page.markdoc +++ b/src/routes/docs/products/auth/teams/+page.markdoc @@ -217,7 +217,7 @@ individual roles in the team using the `Role.team(, [, | Select roles | `Role.team(, [, , ...])`| -{% arrow_link href="/docs/advanced/platform/permissions" %} +{% arrow_link href="/docs/advanced/security/permissions" %} Learn more about permissions {% /arrow_link %} diff --git a/src/routes/docs/products/databases/databases/+page.markdoc b/src/routes/docs/products/databases/databases/+page.markdoc index cc3147838b7..ea3dd1347c5 100644 --- a/src/routes/docs/products/databases/databases/+page.markdoc +++ b/src/routes/docs/products/databases/databases/+page.markdoc @@ -14,7 +14,7 @@ You can create a database by navigating to the **Databases** page and clicking * # Create using Server SDKs {% #create-using-server-sdks %} -You can programmatically create databases using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/platform/api-keys). +You can programmatically create databases using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/security/api-keys). {% multicode %} ```server-nodejs diff --git a/src/routes/docs/products/databases/legacy/collections/+page.markdoc b/src/routes/docs/products/databases/legacy/collections/+page.markdoc index 11bb32ee430..8f8ac951985 100644 --- a/src/routes/docs/products/databases/legacy/collections/+page.markdoc +++ b/src/routes/docs/products/databases/legacy/collections/+page.markdoc @@ -18,7 +18,7 @@ You can create a collection by heading to the **Databases** page, navigate to a {% /tabsitem %} {% tabsitem #server-sdk title="Server SDK" %} -You can also create collections programmatically using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/platform/api-keys). +You can also create collections programmatically using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/security/api-keys). {% multicode %} diff --git a/src/routes/docs/products/databases/legacy/databases/+page.markdoc b/src/routes/docs/products/databases/legacy/databases/+page.markdoc index 084d49064b5..38a11396dc6 100644 --- a/src/routes/docs/products/databases/legacy/databases/+page.markdoc +++ b/src/routes/docs/products/databases/legacy/databases/+page.markdoc @@ -14,7 +14,7 @@ You can create a database by navigating to the **Databases** page and clicking * # Create using Server SDKs {% #create-using-server-sdks %} -You can programmatically create databases using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/platform/api-keys). +You can programmatically create databases using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/security/api-keys). {% multicode %} ```server-nodejs diff --git a/src/routes/docs/products/databases/legacy/permissions/+page.markdoc b/src/routes/docs/products/databases/legacy/permissions/+page.markdoc index 5354078450d..94247a34ec5 100644 --- a/src/routes/docs/products/databases/legacy/permissions/+page.markdoc +++ b/src/routes/docs/products/databases/legacy/permissions/+page.markdoc @@ -17,7 +17,7 @@ If a user has read, create, update, or delete permissions at the collection leve Configure collection level permissions by navigating to **Your collection** > **Settings** > **Permissions**. -[Learn more about permissions and roles](/docs/advanced/platform/permissions) +[Learn more about permissions and roles](/docs/advanced/security/permissions) # Document level {% #document-level %} Document level permissions grant access to individual documents. @@ -28,10 +28,10 @@ Enable document level permissions by navigating to **Your collection** > **Setti Document level permissions are configured in individual documents. -[Learn more about permissions and roles](/docs/advanced/platform/permissions) +[Learn more about permissions and roles](/docs/advanced/security/permissions) # Common use cases {% #common-use-cases %} -For examples of how to implement common permission patterns, including creating private documents that are only accessible to their creators, see the [permissions examples](/docs/advanced/platform/permissions#examples) in our platform documentation. +For examples of how to implement common permission patterns, including creating private documents that are only accessible to their creators, see the [permissions examples](/docs/advanced/security/permissions#examples) in our platform documentation. diff --git a/src/routes/docs/products/databases/permissions/+page.markdoc b/src/routes/docs/products/databases/permissions/+page.markdoc index e6b9ee22b09..4f8901c55a0 100644 --- a/src/routes/docs/products/databases/permissions/+page.markdoc +++ b/src/routes/docs/products/databases/permissions/+page.markdoc @@ -17,7 +17,7 @@ If a user has read, create, update, or delete permissions at the table level, th Configure table level permissions by navigating to **Your table** > **Settings** > **Permissions**. -[Learn more about permissions and roles](/docs/advanced/platform/permissions) +[Learn more about permissions and roles](/docs/advanced/security/permissions) # Row level {% #row-level %} Row level permissions grant access to individual rows. @@ -28,10 +28,10 @@ Enable row level permissions by navigating to **Your table** > **Settings** > ** Row level permissions are configured in individual rows. -[Learn more about permissions and roles](/docs/advanced/platform/permissions) +[Learn more about permissions and roles](/docs/advanced/security/permissions) # Common use cases {% #common-use-cases %} -For examples of how to implement common permission patterns, including creating private rows that are only accessible to their creators, see the [permissions examples](/docs/advanced/platform/permissions#examples) in our platform documentation. +For examples of how to implement common permission patterns, including creating private rows that are only accessible to their creators, see the [permissions examples](/docs/advanced/security/permissions#examples) in our platform documentation. diff --git a/src/routes/docs/products/databases/tables/+page.markdoc b/src/routes/docs/products/databases/tables/+page.markdoc index 1fcff68a5b3..3e6b2fee4df 100644 --- a/src/routes/docs/products/databases/tables/+page.markdoc +++ b/src/routes/docs/products/databases/tables/+page.markdoc @@ -18,7 +18,7 @@ You can create a table by heading to the **Databases** page, navigate to a [data {% /tabsitem %} {% tabsitem #server-sdk title="Server SDK" %} -You can also create tables programmatically using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/platform/api-keys). +You can also create tables programmatically using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/security/api-keys). {% multicode %} diff --git a/src/routes/docs/products/functions/deployments/+page.markdoc b/src/routes/docs/products/functions/deployments/+page.markdoc index 8265c6d193e..cda73fa0f16 100644 --- a/src/routes/docs/products/functions/deployments/+page.markdoc +++ b/src/routes/docs/products/functions/deployments/+page.markdoc @@ -57,8 +57,8 @@ Redeployment behavior varies depending on how the initial deployment was created Users subscribed to the Appwrite Pro plan or above receive certain special benefits: - [Express builds](/changelog/entry/2024-08-10) for quicker deployments, resulting in reduced wait times and smoother workflows -- Longer [build timeouts](/docs/advanced/platform/compute#build-timeouts) (45 minutes vs 15 minutes on Free; Enterprise is custom) -- Customizable [build and runtime specifications](/docs/advanced/platform/compute) for CPU and memory on each function +- Longer [build timeouts](/docs/advanced/billing/compute#build-timeouts) (45 minutes vs 15 minutes on Free; Enterprise is custom) +- Customizable [build and runtime specifications](/docs/advanced/billing/compute) for CPU and memory on each function {% /info %} # Deployment retention {% #deployment-retention %} diff --git a/src/routes/docs/products/functions/develop/+page.markdoc b/src/routes/docs/products/functions/develop/+page.markdoc index 83427b0d894..4c43dfaff88 100644 --- a/src/routes/docs/products/functions/develop/+page.markdoc +++ b/src/routes/docs/products/functions/develop/+page.markdoc @@ -1549,7 +1549,7 @@ Appwrite can be used in your functions by adding the relevant SDK to your functi Authenticating with Appwrite is done via a dynamic API key or a JWT token. ## Dynamic API key {% #dynamic-api-key %} -Dynamic API keys are the same as [API keys](/docs/advanced/platform/api-keys) but are automatically generated. +Dynamic API keys are the same as [API keys](/docs/advanced/security/api-keys) but are automatically generated. They are generated in your functions per execution. However, you can only use dynamic API keys inside Appwrite functions. diff --git a/src/routes/docs/products/functions/environment-variables/+page.markdoc b/src/routes/docs/products/functions/environment-variables/+page.markdoc index e9531515a60..63b7f9fb059 100644 --- a/src/routes/docs/products/functions/environment-variables/+page.markdoc +++ b/src/routes/docs/products/functions/environment-variables/+page.markdoc @@ -8,7 +8,7 @@ Appwrite Functions can read environment variables at build and runtime. Use them A function reads from three sources, in this order of precedence: -1. **Project variables** are shared across every function and site in your project. Set them once and every function inherits them automatically. See [project variables](/docs/advanced/platform/environment-variables) for the platform-wide reference. +1. **Project variables** are shared across every function and site in your project. Set them once and every function inherits them automatically. See [project variables](/docs/advanced/security/environment-variables) for the full reference. 2. **Function variables** are scoped to a single function. Override a project variable for one function by setting the same key on the function itself. 3. **Appwrite-injected variables** are set by Appwrite at execution time (for example, `APPWRITE_FUNCTION_PROJECT_ID`). These take final precedence and cannot be overridden. @@ -31,11 +31,11 @@ Variable changes only take effect on the next deployment. Redeploy your function ![Function environment variables](/images/docs/functions/env-variables.avif) {% /only_light %} -You can also configure global variables that apply to all your functions from your project's **Settings** page. See [project variables](/docs/advanced/platform/environment-variables) for details. +You can also configure global variables that apply to all your functions from your project's **Settings** page. See [project variables](/docs/advanced/security/environment-variables) for details. # Manage with a Server SDK {% #server-sdks %} -You can also manage function variables programmatically using a [Server SDK](/docs/sdks#server). Each call requires an [API key](/docs/advanced/platform/api-keys) with the `functions.write` scope to create, update, or delete variables, or the `functions.read` scope to list and read them. +You can also manage function variables programmatically using a [Server SDK](/docs/sdks#server). Each call requires an [API key](/docs/advanced/security/api-keys) with the `functions.write` scope to create, update, or delete variables, or the `functions.read` scope to list and read them. ## Create a variable {% #create-variable %} diff --git a/src/routes/docs/products/functions/execute/+page.markdoc b/src/routes/docs/products/functions/execute/+page.markdoc index 3a41e6adbb4..c1a46689b46 100644 --- a/src/routes/docs/products/functions/execute/+page.markdoc +++ b/src/routes/docs/products/functions/execute/+page.markdoc @@ -34,7 +34,7 @@ Asynchronous executions are added to a queue and processed by the function worke Asynchronous executions are created via: - The [Create execution](/docs/references/cloud/client-web/functions#createExecution) endpoint where the `async` parameter is `true` -- Event triggers (when functions are triggered by [platform events](/docs/advanced/platform/events)) +- Event triggers (when functions are triggered by [platform events](/docs/advanced/api-integration/events)) - Scheduled executions (cron jobs or delayed executions) Asynchronous executions: @@ -524,7 +524,7 @@ Changes in Appwrite emit events. You can configure Functions to be executed in r 5. Be careful to avoid selecting events that can be caused by the function itself. This can cause the function to trigger its own execution, resulting in infinite recursions. In these executions, the event that triggered the function will be passed as the header `x-appwrite-event` to the function. -The `request.body` parameter will contain the event data. [Learn more about events](/docs/advanced/platform/events). +The `request.body` parameter will contain the event data. [Learn more about events](/docs/advanced/api-integration/events). You can use one of the following events. {% accordion %} @@ -1055,6 +1055,6 @@ async fn main() -> Result<(), Box> { # Permissions {% #permission %} -Appwrite Functions can be executed using Client or Server SDKs. Client SDKs must be authenticated with an account that has been granted execution [permissions](/docs/advanced/platform/permissions) on the function's settings page. Server SDKs require an API key with the correct scopes. +Appwrite Functions can be executed using Client or Server SDKs. Client SDKs must be authenticated with an account that has been granted execution [permissions](/docs/advanced/security/permissions) on the function's settings page. Server SDKs require an API key with the correct scopes. If your function has a generated or custom domain, executions are not authenticated. Anyone visiting the configured domains will be considered a guest, so make sure to give `Any` execute permission in order for domain executions to work. If you need to enforce permissions for functions with a domain, use authentication methods like JWT. diff --git a/src/routes/docs/products/functions/executions/+page.markdoc b/src/routes/docs/products/functions/executions/+page.markdoc index e9b0a6e4852..dcd59f80fdc 100644 --- a/src/routes/docs/products/functions/executions/+page.markdoc +++ b/src/routes/docs/products/functions/executions/+page.markdoc @@ -27,7 +27,7 @@ Here's the information shown on this table. - Timestamp of when the execution was created --- - Trigger -- The [platform event](/docs/advanced/platform/events) that triggered the execution +- The [platform event](/docs/advanced/api-integration/events) that triggered the execution --- - Method - The HTTP method used to create the execution diff --git a/src/routes/docs/products/functions/functions/+page.markdoc b/src/routes/docs/products/functions/functions/+page.markdoc index b2b5de9c388..5b38658ffd2 100644 --- a/src/routes/docs/products/functions/functions/+page.markdoc +++ b/src/routes/docs/products/functions/functions/+page.markdoc @@ -107,11 +107,11 @@ These are terminal commands that will be executed in the runtime containers in t Under **Settings** - **Resource limits**, you can set **build** and **runtime** specifications independently. The build spec applies while your deployment is being built and packaged; the runtime spec applies to each function execution. Both use the same CPU and memory tiers on Cloud. This lets you align compute with heavy dependency installs or compilation without over-provisioning every invocation. -On Appwrite Cloud, customizing specifications requires the **Pro** plan. See [Compute](/docs/advanced/platform/compute) for tiers, GB-hours, and pricing. +On Appwrite Cloud, customizing specifications requires the **Pro** plan. See [Compute](/docs/advanced/billing/compute) for tiers, GB-hours, and pricing. ## Build timeout {% #build-timeout %} -On Appwrite Cloud, the **build** phase of each deployment must complete within your plan’s **maximum build duration** (for example, 15 minutes on Free and 45 minutes on Pro and Scale). See [Build timeouts](/docs/advanced/platform/compute#build-timeouts) and the [pricing page](/pricing). +On Appwrite Cloud, the **build** phase of each deployment must complete within your plan’s **maximum build duration** (for example, 15 minutes on Free and 45 minutes on Pro and Scale). See [Build timeouts](/docs/advanced/billing/compute#build-timeouts) and the [pricing page](/pricing). ## Git integration {% #git-integration %} You can update the entrypoint file and build settings of your function by navigating to your function > **Settings** > **Configuration**. @@ -133,13 +133,13 @@ In production environments, you can choose to disable execution logs to protect ## Execute access {% #execution-access %} You can control who can execute your functions by navigating to your function > **Settings** > **Execute access** -and granting access to select [permission roles](/docs/advanced/platform/permissions#permission-roles). +and granting access to select [permission roles](/docs/advanced/security/permissions#permission-roles). If this is left empty, no user can execute your function. Server SDKs, scheduled executions, and event function triggers don't require permissions to execute a function. ## Events{% #events %} -Functions can be triggered by [platform events](/docs/advanced/platform/events) which reflect changes +Functions can be triggered by [platform events](/docs/advanced/api-integration/events) which reflect changes that occur in your Appwrite project. You can configure events triggers by navigating to your function > **Settings** > **Events**. @@ -168,6 +168,6 @@ There is a system wide maximum timeout of 900 seconds (15 minutes). You can configure the permission scopes for the function [dynamic API key](/docs/products/functions/develop#dynamic-api-key). The dynamic API key is automatically generated to access your project resources like users and buckets but can only be used inside of Appwrite functions. Navigate to your function > **Settings** > **Scopes** to configure your dynamic API key permission scopes. -{% arrow_link href="/docs/advanced/platform/api-keys#scopes" %} +{% arrow_link href="/docs/advanced/security/api-keys#scopes" %} Learn more about scopes {% /arrow_link %} \ No newline at end of file diff --git a/src/routes/docs/products/messaging/topics/+page.markdoc b/src/routes/docs/products/messaging/topics/+page.markdoc index bb31eee9fd8..33f783ebb7c 100644 --- a/src/routes/docs/products/messaging/topics/+page.markdoc +++ b/src/routes/docs/products/messaging/topics/+page.markdoc @@ -322,7 +322,7 @@ Learn more about the CLI topics commands Before you can subscribe to a topic, a user needs the appropriate permission. You can set permission by navigating to **Messaging** > **Topics** > select a topic to configure > **Subscription access**. -{% arrow_link href="/docs/advanced/platform/permissions#permission-roles" %} +{% arrow_link href="/docs/advanced/security/permissions#permission-roles" %} Learn more about permission roles {% /arrow_link %} diff --git a/src/routes/docs/products/network/+layout.svelte b/src/routes/docs/products/network/+layout.svelte index fe7304d018f..3e18199798b 100644 --- a/src/routes/docs/products/network/+layout.svelte +++ b/src/routes/docs/products/network/+layout.svelte @@ -41,6 +41,10 @@ { label: 'Features', items: [ + { + label: 'Custom domains', + href: '/docs/products/network/custom-domains' + }, { label: 'DNS', href: '/docs/products/network/dns' diff --git a/src/routes/docs/products/network/caa-records/+page.markdoc b/src/routes/docs/products/network/caa-records/+page.markdoc index d59532fa143..35b9d92f41f 100644 --- a/src/routes/docs/products/network/caa-records/+page.markdoc +++ b/src/routes/docs/products/network/caa-records/+page.markdoc @@ -6,7 +6,7 @@ description: Learn what DNS Certification Authority Authorization (CAA) records A Certification Authority Authorization (CAA) record is a DNS record that specifies which certificate authorities (CAs) are allowed to issue TLS certificates for your domain. CAA records help prevent unauthorized certificate issuance and are defined in [RFC 8659](https://datatracker.ietf.org/doc/html/rfc8659). -When Appwrite issues a TLS certificate for a [custom domain](/docs/advanced/platform/custom-domains), an [Appwrite Sites domain](/docs/products/sites/domains), or a [Function domain](/docs/products/functions/domains), the certificate authority used by Appwrite checks your domain's CAA records before issuing. If your domain has no CAA records at all, any CA, including Appwrite's, is allowed to issue and no action is needed from you. If your domain already has CAA records and none of them authorize the CA that Appwrite uses, issuance fails and your domain stays unverified until you add the required record. +When Appwrite issues a TLS certificate for a [custom domain](/docs/products/network/custom-domains), an [Appwrite Sites domain](/docs/products/sites/domains), or a [Function domain](/docs/products/functions/domains), the certificate authority used by Appwrite checks your domain's CAA records before issuing. If your domain has no CAA records at all, any CA, including Appwrite's, is allowed to issue and no action is needed from you. If your domain already has CAA records and none of them authorize the CA that Appwrite uses, issuance fails and your domain stays unverified until you add the required record. {% info title="CAA records are additive, not exclusive" %} Adding a CAA record for Appwrite does **not** replace your existing CAA records, override certificates issued by other CAs, or invalidate certificates already in use elsewhere. CAA only controls **future** certificate issuance. You can safely keep every CAA record you already have and add Appwrite's alongside them. See [Setting multiple CAA records](#multiple). diff --git a/src/routes/docs/advanced/platform/custom-domains/+page.markdoc b/src/routes/docs/products/network/custom-domains/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/custom-domains/+page.markdoc rename to src/routes/docs/products/network/custom-domains/+page.markdoc diff --git a/src/routes/docs/products/sites/deployments/+page.markdoc b/src/routes/docs/products/sites/deployments/+page.markdoc index 428d12a4c97..441e97ccbcb 100644 --- a/src/routes/docs/products/sites/deployments/+page.markdoc +++ b/src/routes/docs/products/sites/deployments/+page.markdoc @@ -81,8 +81,8 @@ Redeployment behavior varies depending on how the initial deployment was created Users subscribed to the Appwrite Pro plan or above receive certain special benefits: - [Express builds](/changelog/entry/2024-08-10) for quicker deployments, resulting in reduced wait times and smoother workflows -- Longer [build timeouts](/docs/advanced/platform/compute#build-timeouts) (45 minutes vs 15 minutes on Free; Enterprise is custom) -- Customizable [build and runtime specifications](/docs/advanced/platform/compute) for CPU and memory on each site +- Longer [build timeouts](/docs/advanced/billing/compute#build-timeouts) (45 minutes vs 15 minutes on Free; Enterprise is custom) +- Customizable [build and runtime specifications](/docs/advanced/billing/compute) for CPU and memory on each site {% /info %} # Deployment retention {% #deployment-retention %} diff --git a/src/routes/docs/products/sites/develop/+page.markdoc b/src/routes/docs/products/sites/develop/+page.markdoc index ff9bd7bd93a..fba0eb17a10 100644 --- a/src/routes/docs/products/sites/develop/+page.markdoc +++ b/src/routes/docs/products/sites/develop/+page.markdoc @@ -49,11 +49,11 @@ The default timeout is set at `15 seconds` and the maximum value possible is `30 Under **Settings** - **Resource limits**, you can set **build** and **runtime** specifications independently. The build spec applies while dependencies are installed and your site is built for deployment; the runtime spec applies when your site serves traffic, including server-side rendering (SSR). Both use the same CPU and memory tiers on Cloud. -On Appwrite Cloud, customizing specifications requires the **Pro** plan. See [Compute](/docs/advanced/platform/compute) for tiers, GB-hours, and pricing. +On Appwrite Cloud, customizing specifications requires the **Pro** plan. See [Compute](/docs/advanced/billing/compute) for tiers, GB-hours, and pricing. ## Build timeouts {% #build-timeouts %} -On Appwrite Cloud, the **build** phase of each deployment must complete within your plan’s **maximum build duration** (for example, 15 minutes on Free and 45 minutes on Pro and Scale). See [Build timeouts](/docs/advanced/platform/compute#build-timeouts) and the [pricing page](/pricing). +On Appwrite Cloud, the **build** phase of each deployment must complete within your plan’s **maximum build duration** (for example, 15 minutes on Free and 45 minutes on Pro and Scale). See [Build timeouts](/docs/advanced/billing/compute#build-timeouts) and the [pricing page](/pricing). # Project dependencies diff --git a/src/routes/docs/products/sites/environment-variables/+page.markdoc b/src/routes/docs/products/sites/environment-variables/+page.markdoc index e504120b862..c10d6a825f5 100644 --- a/src/routes/docs/products/sites/environment-variables/+page.markdoc +++ b/src/routes/docs/products/sites/environment-variables/+page.markdoc @@ -8,7 +8,7 @@ Appwrite Sites can read environment variables at build and runtime. Use them to A site reads from three sources, in this order of precedence: -1. **Project variables** are shared across every function and site in your project. Set them once and every site inherits them automatically. See [project variables](/docs/advanced/platform/environment-variables) for the platform-wide reference. +1. **Project variables** are shared across every function and site in your project. Set them once and every site inherits them automatically. See [project variables](/docs/advanced/security/environment-variables) for the full reference. 2. **Site variables** are scoped to a single site. Override a project variable for one site by setting the same key on the site itself. 3. **Appwrite-injected variables** are set by Appwrite at deployment time (for example, `APPWRITE_SITE_PROJECT_ID`). These take final precedence and cannot be overridden. @@ -31,11 +31,11 @@ Variable changes only take effect on the next deployment. Redeploy your site aft ![Site environment variables](/images/docs/sites/env-variables.avif) {% /only_light %} -You can also configure global variables that apply to all your sites from your project's **Settings** page. See [project variables](/docs/advanced/platform/environment-variables) for details. +You can also configure global variables that apply to all your sites from your project's **Settings** page. See [project variables](/docs/advanced/security/environment-variables) for details. # Manage with a Server SDK {% #server-sdks %} -You can also manage site variables programmatically using a [Server SDK](/docs/sdks#server). Each call requires an [API key](/docs/advanced/platform/api-keys) with the `sites.write` scope to create, update, or delete variables, or the `sites.read` scope to list and read them. +You can also manage site variables programmatically using a [Server SDK](/docs/sdks#server). Each call requires an [API key](/docs/advanced/security/api-keys) with the `sites.write` scope to create, update, or delete variables, or the `sites.read` scope to list and read them. ## Create a variable {% #create-variable %} diff --git a/src/routes/docs/products/storage/buckets/+page.markdoc b/src/routes/docs/products/storage/buckets/+page.markdoc index 2609ca305b3..fb5f76e4947 100644 --- a/src/routes/docs/products/storage/buckets/+page.markdoc +++ b/src/routes/docs/products/storage/buckets/+page.markdoc @@ -23,7 +23,7 @@ You can create a bucket by heading to the **Storage** page and clicking **Create {% /tabsitem %} {% tabsitem #server-sdk title="Server SDK" %} -You can also create tables programmatically using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/platform/api-keys). +You can also create tables programmatically using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/security/api-keys). {% multicode %} diff --git a/src/routes/docs/products/storage/file-tokens/+page.markdoc b/src/routes/docs/products/storage/file-tokens/+page.markdoc index 852c0b41ace..1c08c572d3b 100644 --- a/src/routes/docs/products/storage/file-tokens/+page.markdoc +++ b/src/routes/docs/products/storage/file-tokens/+page.markdoc @@ -41,7 +41,7 @@ You can then click on the three-dots menu, click on **Copy URL** and get the tok {% tabsitem #server-sdk title="Server SDK" %} -You can create file tokens programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#createFileToken). Appwrite's Server SDKs require an [API key](/docs/advanced/platform/api-keys) with the `tokens.write` scope enabled. +You can create file tokens programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#createFileToken). Appwrite's Server SDKs require an [API key](/docs/advanced/security/api-keys) with the `tokens.write` scope enabled. {% multicode %} ```server-nodejs @@ -345,7 +345,7 @@ Head to the **Storage** page, open a file inside a bucket, and scroll down to th {% tabsitem #server-sdk title="Server SDK" %} -You can list all file tokens programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#list). Appwrite's Server SDKs require an [API key](/docs/advanced/platform/api-keys) with the `tokens.read` scope enabled. +You can list all file tokens programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#list). Appwrite's Server SDKs require an [API key](/docs/advanced/security/api-keys) with the `tokens.read` scope enabled. {% multicode %} ```server-nodejs @@ -724,7 +724,7 @@ Head to the **Storage** page, open a file inside a bucket, and scroll down to th {% tabsitem #server-sdk title="Server SDK" %} -You can update file token expiry programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#update). Appwrite's Server SDKs require an [API key](/docs/advanced/platform/api-keys) with the `tokens.write` scope enabled. +You can update file token expiry programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#update). Appwrite's Server SDKs require an [API key](/docs/advanced/security/api-keys) with the `tokens.write` scope enabled. {% multicode %} ```server-nodejs @@ -1014,7 +1014,7 @@ Head to the **Storage** page, open a file inside a bucket, and scroll down to th {% tabsitem #server-sdk title="Server SDK" %} -You can delete a file token programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#delete). Appwrite's Server SDKs require an [API key](/docs/advanced/platform/api-keys) with the `tokens.write` scope enabled. +You can delete a file token programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#delete). Appwrite's Server SDKs require an [API key](/docs/advanced/security/api-keys) with the `tokens.write` scope enabled. {% multicode %} ```server-nodejs diff --git a/src/routes/docs/products/storage/permissions/+page.markdoc b/src/routes/docs/products/storage/permissions/+page.markdoc index e948c54267c..8a84d80fd53 100644 --- a/src/routes/docs/products/storage/permissions/+page.markdoc +++ b/src/routes/docs/products/storage/permissions/+page.markdoc @@ -17,7 +17,7 @@ If a user has read, create, update, or delete permissions at the bucket level, t Configure bucket level permissions by navigating to **Your bucket** > **Settings** > **Permissions**. -[Learn more about permissions and roles](/docs/advanced/platform/permissions) +[Learn more about permissions and roles](/docs/advanced/security/permissions) # File level {% #file-level %} File level permissions grant access to individual files. @@ -28,6 +28,6 @@ Enable file level permissions by navigating to **Your bucket** > **Settings** > File level permissions are configured in individual [files](/docs/products/storage/permissions#file-level). -[Learn more about permissions and roles](/docs/advanced/platform/permissions) +[Learn more about permissions and roles](/docs/advanced/security/permissions) diff --git a/src/routes/docs/quick-starts/flutter/+page.markdoc b/src/routes/docs/quick-starts/flutter/+page.markdoc index a85051b34cb..2f193925940 100644 --- a/src/routes/docs/quick-starts/flutter/+page.markdoc +++ b/src/routes/docs/quick-starts/flutter/+page.markdoc @@ -56,7 +56,7 @@ The callbackUrlScheme parameter in the authenticate() method isn't applicable wh {% info title="Flutter web cross-domain communication & cookies" %} While running Flutter Web, make sure your Appwrite project and your Flutter client use the same top-level domain and protocol (HTTP or HTTPS) to communicate. When communicating between different domains or protocols, you may receive HTTP status error 401 because some modern browsers block cross-site or insecure cookies for enhanced privacy. -In production, Appwrite allows you to set multiple [custom-domains](/docs/advanced/platform/custom-domains) for each project. +In production, Appwrite allows you to set multiple [custom-domains](/docs/products/network/custom-domains) for each project. {% /info %} {% /tabsitem %} diff --git a/src/routes/docs/references/+page.markdoc b/src/routes/docs/references/+page.markdoc index 2af04b21bc6..a14c1bb4a4f 100644 --- a/src/routes/docs/references/+page.markdoc +++ b/src/routes/docs/references/+page.markdoc @@ -8,15 +8,15 @@ Appwrite lets you build integrations on web, mobile, native, and server platform ## Client vs Server APIs {% #client-vs-server %} Client APIs and SDKs are for integrating with Appwrite to build client-based applications and websites. -Client APIs only give access to resources if users have been [granted permissions](/docs/advanced/platform/permissions). +Client APIs only give access to resources if users have been [granted permissions](/docs/advanced/security/permissions). Server API and SDKs are for integrating with Appwrite to build backend or server applications. -Server APIs are constrained by an [API key's](/docs/advanced/platform/api-keys) scope, ignoring user permissions. +Server APIs are constrained by an [API key's](/docs/advanced/security/api-keys) scope, ignoring user permissions. ## APIs {% #api %} Before using the Appwrite APIs, in the **Settings** of your Appwrite project, obtain your **API endpoint** and **Project ID**. Client APIs require an active session, created from [signing up and logging in](/docs/products/auth/accounts#signup-login). -Server APIs require [API keys](/docs/advanced/platform/api-keys). +Server APIs require [API keys](/docs/advanced/security/api-keys). {% only_dark %} @@ -70,4 +70,4 @@ Track which signed-in users are active right now and broadcast their status in r ## Error handling {% #error-handling %} -When building with Appwrite, implement proper error handling to provide user-friendly messages instead of exposing raw error responses. For implementation details and best practices, refer to our [Error handling guide](/docs/advanced/platform/error-handling) and [Response codes](/docs/advanced/platform/response-codes#error-types) documentation. +When building with Appwrite, implement proper error handling to provide user-friendly messages instead of exposing raw error responses. For implementation details and best practices, refer to our [Error handling guide](/docs/advanced/api-integration/error-handling) and [Response codes](/docs/advanced/api-integration/response-codes#error-types) documentation. diff --git a/src/routes/docs/references/[version]/[platform]/[service]/(components)/RateLimits.svelte b/src/routes/docs/references/[version]/[platform]/[service]/(components)/RateLimits.svelte index 240ce2af461..b21f6135974 100644 --- a/src/routes/docs/references/[version]/[platform]/[service]/(components)/RateLimits.svelte +++ b/src/routes/docs/references/[version]/[platform]/[service]/(components)/RateLimits.svelte @@ -106,7 +106,7 @@
trackEvent(`docs-rate_limits_learn_more-click`)} > diff --git a/src/routes/docs/references/[version]/[platform]/[service]/descriptions/presences.md b/src/routes/docs/references/[version]/[platform]/[service]/descriptions/presences.md index b0d19728eab..fca575713c8 100644 --- a/src/routes/docs/references/[version]/[platform]/[service]/descriptions/presences.md +++ b/src/routes/docs/references/[version]/[platform]/[service]/descriptions/presences.md @@ -1,5 +1,5 @@ The Presences service records a short-lived status for each signed-in user and broadcasts every change over [Realtime](/docs/apis/realtime), so you can render online indicators, "viewing this page" cues, typing signals, and collaboration banners without writing any socket plumbing. -Each presence is attached to a user and carries a `status` string, an optional `metadata` JSON object for richer context, and an `expiresAt` timestamp that controls automatic cleanup. Presences are written by the user's own session or a server SDK, and read by any client with the right [permissions](/docs/advanced/platform/permissions). +Each presence is attached to a user and carries a `status` string, an optional `metadata` JSON object for richer context, and an `expiresAt` timestamp that controls automatic cleanup. Presences are written by the user's own session or a server SDK, and read by any client with the right [permissions](/docs/advanced/security/permissions). You can find guides and examples on using the Presences API in the [Presences product pages](/docs/products/auth/presences). diff --git a/src/routes/docs/references/[version]/[platform]/[service]/descriptions/storage.md b/src/routes/docs/references/[version]/[platform]/[service]/descriptions/storage.md index 18bf27abff1..322c3e032d3 100644 --- a/src/routes/docs/references/[version]/[platform]/[service]/descriptions/storage.md +++ b/src/routes/docs/references/[version]/[platform]/[service]/descriptions/storage.md @@ -4,6 +4,6 @@ Large files are uploaded in 5MB chunks. Appwrite SDKs handle chunking for you an Files are managed using buckets. Storage buckets are similar to Tables we have in our [Databases](/docs/products/databases) service. The difference is, buckets also provide more power to decide what kinds of files, what sizes you want to allow in that bucket, whether or not to encrypt the files, scan with antivirus and more. -Using Appwrite permissions architecture, you can assign read or write access to each bucket or file in your project for either a specific user, team, user role, or even grant it with public access (`any`). You can learn more about [how Appwrite handles permissions and access control](/docs/advanced/platform/permissions). +Using Appwrite permissions architecture, you can assign read or write access to each bucket or file in your project for either a specific user, team, user role, or even grant it with public access (`any`). You can learn more about [how Appwrite handles permissions and access control](/docs/advanced/security/permissions). The preview endpoint allows you to generate preview images for your files. Using the preview endpoint, you can also manipulate the resulting image so that it will fit perfectly inside your app in terms of dimensions, file size, and style. The preview endpoint also allows you to change the resulting image file format for better compression or image quality for better delivery over the network. diff --git a/src/routes/docs/references/[version]/[platform]/[service]/descriptions/teams.md b/src/routes/docs/references/[version]/[platform]/[service]/descriptions/teams.md index a0262fc5ff0..996933c2a55 100644 --- a/src/routes/docs/references/[version]/[platform]/[service]/descriptions/teams.md +++ b/src/routes/docs/references/[version]/[platform]/[service]/descriptions/teams.md @@ -1,3 +1,3 @@ -The Teams service allows you to group users of your project and share [read and write](/docs/advanced/platform/permissions) access to resources like database rows or storage files. +The Teams service allows you to group users of your project and share [read and write](/docs/advanced/security/permissions) access to resources like database rows or storage files. Each user who creates a team becomes the team owner and can delegate the ownership role by inviting a new team member. Only team owners can invite new users to their team. diff --git a/src/routes/docs/references/quick-start/+page.markdoc b/src/routes/docs/references/quick-start/+page.markdoc index d30febc15b9..080b067fd65 100644 --- a/src/routes/docs/references/quick-start/+page.markdoc +++ b/src/routes/docs/references/quick-start/+page.markdoc @@ -260,7 +260,7 @@ Admin clients should only be used if you need to perform admin actions that bypa or [unauthenticated requests that bypass rate limits](/docs/products/auth/server-side-rendering#rate-limits). {% /info %} -To initialize the admin client, we'll need to first [generated an API key](/docs/advanced/platform/api-keys#create-api-key). +To initialize the admin client, we'll need to first [generated an API key](/docs/advanced/security/api-keys#create-api-key). The API key should have the following scope in order to perform authentication: | Category {% width=120 %} | Required scopes | Purpose | @@ -297,7 +297,7 @@ let admin_client = Client::new() ``` {% /multicode %} -It is important to use an API key, as this will allow your server requests to bypass [rate limits](/docs/advanced/platform/rate-limits). If you don't use an API key, your server will be rate limited as if it were a client from a single IP address. +It is important to use an API key, as this will allow your server requests to bypass [rate limits](/docs/advanced/security/rate-limits). If you don't use an API key, your server will be rate limited as if it were a client from a single IP address. ## Session client {% #session-client %} diff --git a/src/routes/docs/sdks/+page.markdoc b/src/routes/docs/sdks/+page.markdoc index 5ad3c160477..bcd888b80b9 100644 --- a/src/routes/docs/sdks/+page.markdoc +++ b/src/routes/docs/sdks/+page.markdoc @@ -590,7 +590,7 @@ You can discover the available enums in each SDK at the source. ## Queries and permissions {% #queries-and-permissions %} Appwrite has utility classes for queries and permissions. -You can learn more about [query utility classes](/docs/products/databases/queries) and [permissions utility classes](/docs/advanced/platform/permissions) in their own pages. +You can learn more about [query utility classes](/docs/products/databases/queries) and [permissions utility classes](/docs/advanced/security/permissions) in their own pages. ## File I/O {% #file-io %} Depending on your platform, you will also need some helpers to interface with system I/O. diff --git a/src/routes/docs/tooling/ai/responsible-ai/+page.markdoc b/src/routes/docs/tooling/ai/responsible-ai/+page.markdoc index cef7217eb07..38abbdd55d4 100644 --- a/src/routes/docs/tooling/ai/responsible-ai/+page.markdoc +++ b/src/routes/docs/tooling/ai/responsible-ai/+page.markdoc @@ -12,7 +12,7 @@ When sending data to AI providers like OpenAI, Anthropic, or others, be mindful - **Avoid sending personal data** to AI providers unless necessary for the feature. Strip personally identifiable information (PII) like names, emails, and addresses from prompts before sending them to an LLM. - **Review provider data policies** to understand how each AI provider handles the data you send. Some providers use input data for model training unless you opt out. -- **Use Appwrite permissions** to control which users and roles can trigger AI-powered features. Appwrite's [permission system](/docs/advanced/platform/permissions) lets you restrict access at the database, storage, and function level. +- **Use Appwrite permissions** to control which users and roles can trigger AI-powered features. Appwrite's [permission system](/docs/advanced/security/permissions) lets you restrict access at the database, storage, and function level. # Secure your API keys {% #secure-api-keys %} diff --git a/src/routes/docs/tooling/command-center/+layout.svelte b/src/routes/docs/tooling/command-center/+layout.svelte index 93e22c8cebf..928dc1300c8 100644 --- a/src/routes/docs/tooling/command-center/+layout.svelte +++ b/src/routes/docs/tooling/command-center/+layout.svelte @@ -1,9 +1,30 @@ - + diff --git a/src/routes/docs/advanced/platform/shortcuts/+page.markdoc b/src/routes/docs/tooling/command-center/shortcuts/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/shortcuts/+page.markdoc rename to src/routes/docs/tooling/command-center/shortcuts/+page.markdoc diff --git a/src/routes/docs/tooling/command-line/non-interactive/+page.markdoc b/src/routes/docs/tooling/command-line/non-interactive/+page.markdoc index cb11d9072dc..b5a6dc9ac5f 100644 --- a/src/routes/docs/tooling/command-line/non-interactive/+page.markdoc +++ b/src/routes/docs/tooling/command-line/non-interactive/+page.markdoc @@ -17,7 +17,7 @@ When you set the global configuration parameters using the `appwrite client` com In this mode, the CLI can only interact with one project at a time. # API Keys {% #api-keys %} -In non-interactive mode, the CLI uses an API key to authenticate. Your API key must have sufficient permissions to execute the commands you plan to use. [Learn more about API Keys](/docs/advanced/platform/api-keys). +In non-interactive mode, the CLI uses an API key to authenticate. Your API key must have sufficient permissions to execute the commands you plan to use. [Learn more about API Keys](/docs/advanced/security/api-keys). # Deployment {% #deployment %} Appwrite's `push` commands can also be executed in a non-interactive mode. This applies to the following resources: functions, tables, buckets, teams, and messaging topics. diff --git a/src/routes/docs/tooling/terraform/resources/webhooks/+page.markdoc b/src/routes/docs/tooling/terraform/resources/webhooks/+page.markdoc index d993301adb0..5905f7827e4 100644 --- a/src/routes/docs/tooling/terraform/resources/webhooks/+page.markdoc +++ b/src/routes/docs/tooling/terraform/resources/webhooks/+page.markdoc @@ -40,7 +40,7 @@ resource "appwrite_webhook" "authenticated" { } ``` -Use the read-only **`secret`** attribute when configuring **signature verification** for payloads Appwrite sends to your URL (see [Webhooks](/docs/advanced/platform/webhooks) in the platform docs). +Use the read-only **`secret`** attribute when configuring **signature verification** for payloads Appwrite sends to your URL (see [Webhooks](/docs/advanced/api-integration/webhooks) in the platform docs). # Data sources {% #data-sources %} @@ -61,4 +61,4 @@ See the [Terraform Registry](https://registry.terraform.io/providers/appwrite/ap # Related {% #related %} - [Configuration](/docs/tooling/terraform/provider): authentication and endpoints -- [Webhooks](/docs/advanced/platform/webhooks): event delivery, headers, and signatures +- [Webhooks](/docs/advanced/api-integration/webhooks): event delivery, headers, and signatures diff --git a/src/routes/docs/tutorials/subscriptions-with-stripe/step-5/+page.markdoc b/src/routes/docs/tutorials/subscriptions-with-stripe/step-5/+page.markdoc index 2136213889e..89437fd1b03 100644 --- a/src/routes/docs/tutorials/subscriptions-with-stripe/step-5/+page.markdoc +++ b/src/routes/docs/tutorials/subscriptions-with-stripe/step-5/+page.markdoc @@ -52,6 +52,6 @@ The label created will grant the user access to any resource with the following | Delete | `Permissions.delete(Role.label('subscriber'))` | | Create | `Permissions.create(Role.label('subscriber'))` | -{% arrow_link href="/docs/advanced/platform/permissions" %} +{% arrow_link href="/docs/advanced/security/permissions" %} Learn more about permissions {% /arrow_link %} \ No newline at end of file diff --git a/src/routes/llms-full.txt/+server.ts b/src/routes/llms-full.txt/+server.ts index 9e7c33134a9..0e291a0e858 100644 --- a/src/routes/llms-full.txt/+server.ts +++ b/src/routes/llms-full.txt/+server.ts @@ -124,7 +124,7 @@ ${page.fullContent} } // Skip stub pages with no useful content - if (href === '/docs/advanced/integration' || href === '/blog/category/integrations') { + if (href === '/blog/category/integrations') { continue; } diff --git a/src/routes/llms.txt/+server.ts b/src/routes/llms.txt/+server.ts index fab781cbfe5..a34272a8eeb 100644 --- a/src/routes/llms.txt/+server.ts +++ b/src/routes/llms.txt/+server.ts @@ -144,7 +144,7 @@ export const GET: RequestHandler = ({ request }) => { } // Skip stub pages with no useful content - if (href === '/docs/advanced/integration' || href === '/blog/category/integrations') { + if (href === '/blog/category/integrations') { continue; } diff --git a/src/routes/pricing/compare-plans.svelte b/src/routes/pricing/compare-plans.svelte index b5f09a09423..61d80712d7c 100644 --- a/src/routes/pricing/compare-plans.svelte +++ b/src/routes/pricing/compare-plans.svelte @@ -177,12 +177,12 @@ free: '-', pro: { text: 'View rates', - url: '/docs/advanced/platform/phone-otp#rates', + url: '/docs/advanced/billing/phone-otp#rates', event: 'pricing-pro-view_phone_otp_rates-click' }, scale: { text: 'View rates', - url: '/docs/advanced/platform/phone-otp#rates', + url: '/docs/advanced/billing/phone-otp#rates', event: 'pricing-scale-view_phone_otp_rates-click' }, enterprise: 'Custom' diff --git a/src/routes/pricing/faq.svelte b/src/routes/pricing/faq.svelte index 5adfc0b762b..5c9c03935c0 100644 --- a/src/routes/pricing/faq.svelte +++ b/src/routes/pricing/faq.svelte @@ -14,15 +14,15 @@ // }, { question: 'What payment methods does Appwrite support?', - answer: 'Appwrite currently supports credit and debit card payments. We are actively working on adding support for more methods. Please contact us in case this is an issue for you.' + answer: 'Appwrite currently supports credit and debit card payments. We are actively working on adding support for more methods. Please contact us in case this is an issue for you.' }, { question: 'What happens if I reach a resource limit in my Pro plan?', - answer: 'Your project will continue to run, and additional charges will apply. You can find the costs for additional resources in the pricing plans comparison. We will also send you email reminders when you hit 75% and 100% of your resource limits. To avoid unexpected payments, you can set up a budget cap on your organization. Learn more in our docs.' + answer: 'Your project will continue to run, and additional charges will apply. You can find the costs for additional resources in the pricing plans comparison. We will also send you email reminders when you hit 75% and 100% of your resource limits. To avoid unexpected payments, you can set up a budget cap on your organization. Learn more in our docs.' }, { question: 'What happens if I reach a resource limit in my Free plan?', - answer: 'Your project will freeze, and Appwrite Console will continue running in read-only mode. You need to upgrade to Pro, remove resources that exceed their limit, or wait for the next billing cycle, which resets usage limits. Learn more in our docs.' + answer: 'Your project will freeze, and Appwrite Console will continue running in read-only mode. You need to upgrade to Pro, remove resources that exceed their limit, or wait for the next billing cycle, which resets usage limits. Learn more in our docs.' }, { question: 'Why does Appwrite ask for payment verification for up to $150?', diff --git a/src/routes/products/auth/(components)/Access.svelte b/src/routes/products/auth/(components)/Access.svelte index 4700328a38f..1eb79bda7a8 100644 --- a/src/routes/products/auth/(components)/Access.svelte +++ b/src/routes/products/auth/(components)/Access.svelte @@ -35,7 +35,7 @@ Create custom roles and level of access to resources such as projects, files, etc.

mock phone numbers to test OTP functionality without incurring costs. Please refer to our rates page for a breakdown of the pricing, including rates by region and specific SMS costs.' + answer: 'OTP SMS messages are billed per message sent. You can use mock phone numbers to test OTP functionality without incurring costs. Please refer to our rates page for a breakdown of the pricing, including rates by region and specific SMS costs.' }, { question: 'What happens if we scale overnight?', diff --git a/src/routes/terms/+page.markdoc b/src/routes/terms/+page.markdoc index 5333d45d7ed..7d105587b8b 100644 --- a/src/routes/terms/+page.markdoc +++ b/src/routes/terms/+page.markdoc @@ -34,7 +34,7 @@ Your continued use of the Service after the Subscription fee change comes into e Certain refund requests for Subscriptions may be considered by Appwrite on a case-by-case basis and granted in the sole discretion of Appwrite. -For more details, refer to the [full refund policy](/docs/advanced/platform/refund-policy). +For more details, refer to the [full refund policy](/docs/advanced/billing/refund-policy). # Content From 3cafd2531b91e4f4794f1207b386b7c2a1fb9078 Mon Sep 17 00:00:00 2001 From: adityaoberai Date: Thu, 4 Jun 2026 01:41:14 +0530 Subject: [PATCH 06/61] Shift Roles docs to Advanced > Security --- src/redirects.json | 2 +- .../+page.markdoc | 2 +- src/routes/docs/advanced/security/+layout.svelte | 4 ++++ src/routes/docs/advanced/security/+page.markdoc | 4 ++++ .../{products/auth => advanced/security}/roles/+page.markdoc | 0 src/routes/docs/products/auth/+layout.svelte | 4 ---- 6 files changed, 10 insertions(+), 6 deletions(-) rename src/routes/docs/{products/auth => advanced/security}/roles/+page.markdoc (100%) diff --git a/src/redirects.json b/src/redirects.json index 9ca53703efe..e6c8d4f085b 100644 --- a/src/redirects.json +++ b/src/redirects.json @@ -970,7 +970,7 @@ }, { "link": "/docs/advanced/platform/roles", - "redirect": "/docs/products/auth/roles" + "redirect": "/docs/advanced/security/roles" }, { "link": "/docs/advanced/platform/message-templates", diff --git a/src/routes/blog/post/what-developers-actually-want-from-a-backend-platform/+page.markdoc b/src/routes/blog/post/what-developers-actually-want-from-a-backend-platform/+page.markdoc index a0f19f21edf..fe8a7eba35f 100644 --- a/src/routes/blog/post/what-developers-actually-want-from-a-backend-platform/+page.markdoc +++ b/src/routes/blog/post/what-developers-actually-want-from-a-backend-platform/+page.markdoc @@ -96,7 +96,7 @@ A backend platform should handle the following by default: - Rate limiting on authentication endpoints - Session management with configurable expiry -Appwrite's [permissions model](/docs/products/databases/permissions) operates at the table and row-level. Combined with [roles and labels](/docs/products/auth/roles) on user accounts, you can model granular access patterns without writing custom middleware for every endpoint. +Appwrite's [permissions model](/docs/products/databases/permissions) operates at the table and row-level. Combined with [roles and labels](/docs/advanced/security/roles) on user accounts, you can model granular access patterns without writing custom middleware for every endpoint. # Scalability from first commit to production diff --git a/src/routes/docs/advanced/security/+layout.svelte b/src/routes/docs/advanced/security/+layout.svelte index 77154195a84..a2ae4390282 100644 --- a/src/routes/docs/advanced/security/+layout.svelte +++ b/src/routes/docs/advanced/security/+layout.svelte @@ -90,6 +90,10 @@ label: 'Permissions', href: '/docs/advanced/security/permissions' }, + { + label: 'Roles', + href: '/docs/advanced/security/roles' + }, { label: 'Rate limits', href: '/docs/advanced/security/rate-limits' diff --git a/src/routes/docs/advanced/security/+page.markdoc b/src/routes/docs/advanced/security/+page.markdoc index 57586ef4c6f..53173a62f4c 100644 --- a/src/routes/docs/advanced/security/+page.markdoc +++ b/src/routes/docs/advanced/security/+page.markdoc @@ -101,6 +101,10 @@ access control and prevent abuse. Control which users can access which resources. {% /cards_item %} +{% cards_item href="/docs/advanced/security/roles" title="Roles" %} +Learn about Console organization member roles and the access each one grants. +{% /cards_item %} + {% cards_item href="/docs/advanced/security/rate-limits" title="Rate limits" %} Appwrite has rate limits on some endpoints to prevent abuse. {% /cards_item %} diff --git a/src/routes/docs/products/auth/roles/+page.markdoc b/src/routes/docs/advanced/security/roles/+page.markdoc similarity index 100% rename from src/routes/docs/products/auth/roles/+page.markdoc rename to src/routes/docs/advanced/security/roles/+page.markdoc diff --git a/src/routes/docs/products/auth/+layout.svelte b/src/routes/docs/products/auth/+layout.svelte index eb515ad35bb..0f6dfbc4548 100644 --- a/src/routes/docs/products/auth/+layout.svelte +++ b/src/routes/docs/products/auth/+layout.svelte @@ -37,10 +37,6 @@ label: 'Teams', href: '/docs/products/auth/teams' }, - { - label: 'Roles', - href: '/docs/products/auth/roles' - }, { label: 'Impersonation', href: '/docs/products/auth/impersonation', From 52e1031a27da1de01db67ce26dd9bbcba4a7edea Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 5 Jun 2026 16:56:59 +0530 Subject: [PATCH 07/61] Update admin client docs for helpers.createAdminClient Reflects the new framework helper method that returns the full node-appwrite AdminServer (users, databases, storage, teams, and the rest). Hub keeps the standalone createAdminClient as an alternative. --- .../+page.markdoc | 10 ++++---- .../docs/products/auth/react/+page.markdoc | 24 +++++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc index 8e1a23d1853..a2128427d32 100644 --- a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc +++ b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc @@ -112,15 +112,17 @@ if (session) { # Admin client -Server entrypoints also expose `createAdminClient`, which returns a `node-appwrite` client authenticated with your project API key. It is the same client you would write yourself, just with the environment wiring done for you, so the rest of your server code keeps using the official Node SDK. +For privileged operations, pass an `apiKey` into the framework helper and call `createAdminClient()` on it. The returned object exposes every `node-appwrite` service (`users`, `databases`, `storage`, `teams`, `functions`, and so on), so the rest of your server code keeps using the official Node SDK. ```ts -const admin = createAdminClient({ - ...appwrite, +const helpers = createNextServerHelpers({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, apiKey: process.env.APPWRITE_API_KEY!, }); -const users = await admin.account.list(); +const admin = helpers.createAdminClient(); +const users = await admin.users.list(); ``` # Where to start diff --git a/src/routes/docs/products/auth/react/+page.markdoc b/src/routes/docs/products/auth/react/+page.markdoc index ff8498f6a20..8dfa2a1bac3 100644 --- a/src/routes/docs/products/auth/react/+page.markdoc +++ b/src/routes/docs/products/auth/react/+page.markdoc @@ -254,7 +254,8 @@ Both return an object with: | `readSessionCookie()` | `string \| undefined` (sync on TanStack, async on Next.js) | The session secret. Pass it into `AppwriteProvider`'s `ssr.session` prop. | | `getLoggedInUser()` | `Models.User \| null` | The current user, fetched via the cookie. Returns `null` on 401. | | `getSession()` | `Models.Session \| null` | The current session row. | -| `createSessionClient()` | `{ client, account } \| null` | A `node-appwrite` client authenticated as the cookie's user, or `null` if no cookie. | +| `createSessionClient()` | `NodeSessionServer \| null` | A `node-appwrite` client authenticated as the cookie's user, or `null` if no cookie. | +| `createAdminClient()` | `AdminServer` | A `node-appwrite` admin client authenticated with the API key passed to the helper. Throws if `apiKey` is not configured. | ## Session client {% #session-client %} @@ -277,10 +278,25 @@ if (session) { ## Admin client {% #admin-client %} -For privileged operations (creating users, listing sessions, managing teams) import `createAdminClient` from the framework-specific server entrypoint. It returns a `node-appwrite` client authenticated with your API key. +For privileged operations (creating users, listing sessions, managing teams) call `createAdminClient` on the framework helper. Pass `apiKey` in the helper config to enable it, then call the method anywhere on the server. The returned object exposes every `node-appwrite` service: `account`, `users`, `databases`, `storage`, `teams`, `functions`, `messaging`, `tablesDB`, and more. ```ts -import { createAdminClient } from "@appwrite.io/react/server/next"; +import { createNextServerHelpers } from "@appwrite.io/react/server/next"; + +const helpers = createNextServerHelpers({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + apiKey: process.env.APPWRITE_API_KEY!, +}); + +const admin = helpers.createAdminClient(); +const users = await admin.users.list(); +``` + +If you would rather not pass the API key into the helper, the library also exports a standalone `createAdminClient` from `@appwrite.io/react/server` that takes the key directly. + +```ts +import { createAdminClient } from "@appwrite.io/react/server"; const admin = createAdminClient({ endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, @@ -288,7 +304,7 @@ const admin = createAdminClient({ apiKey: process.env.APPWRITE_API_KEY!, }); -const users = await admin.account.list(); +const users = await admin.users.list(); ``` Never import any `@appwrite.io/react/server/*` module from client code: the entrypoints are marked `server-only` and will throw if bundled into the browser. From c51c331066769094f3147e8a5b076a2607860681 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 5 Jun 2026 17:15:00 +0530 Subject: [PATCH 08/61] Note createAdminClient requires apiKey in helper config --- src/routes/docs/products/auth/react/+page.markdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/docs/products/auth/react/+page.markdoc b/src/routes/docs/products/auth/react/+page.markdoc index 8dfa2a1bac3..48e20ac306e 100644 --- a/src/routes/docs/products/auth/react/+page.markdoc +++ b/src/routes/docs/products/auth/react/+page.markdoc @@ -255,7 +255,7 @@ Both return an object with: | `getLoggedInUser()` | `Models.User \| null` | The current user, fetched via the cookie. Returns `null` on 401. | | `getSession()` | `Models.Session \| null` | The current session row. | | `createSessionClient()` | `NodeSessionServer \| null` | A `node-appwrite` client authenticated as the cookie's user, or `null` if no cookie. | -| `createAdminClient()` | `AdminServer` | A `node-appwrite` admin client authenticated with the API key passed to the helper. Throws if `apiKey` is not configured. | +| `createAdminClient()` | `AdminServer` | A `node-appwrite` admin client authenticated with the API key passed to the helper. Only available when `apiKey` is set in the helper config. | ## Session client {% #session-client %} From a804856ae5ccdeea52ff13d4305dd6c8150c5936 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 5 Jun 2026 17:26:21 +0530 Subject: [PATCH 09/61] Promote tablesDB over legacy databases in prose --- .../blog/post/announcing-appwrite-react-library/+page.markdoc | 2 +- src/routes/docs/products/auth/react/+page.markdoc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc index a2128427d32..62756ee3bd1 100644 --- a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc +++ b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc @@ -112,7 +112,7 @@ if (session) { # Admin client -For privileged operations, pass an `apiKey` into the framework helper and call `createAdminClient()` on it. The returned object exposes every `node-appwrite` service (`users`, `databases`, `storage`, `teams`, `functions`, and so on), so the rest of your server code keeps using the official Node SDK. +For privileged operations, pass an `apiKey` into the framework helper and call `createAdminClient()` on it. The returned object exposes every `node-appwrite` service (`users`, `tablesDB`, `storage`, `teams`, `functions`, and so on), so the rest of your server code keeps using the official Node SDK. ```ts const helpers = createNextServerHelpers({ diff --git a/src/routes/docs/products/auth/react/+page.markdoc b/src/routes/docs/products/auth/react/+page.markdoc index 48e20ac306e..9af7ceaeaa5 100644 --- a/src/routes/docs/products/auth/react/+page.markdoc +++ b/src/routes/docs/products/auth/react/+page.markdoc @@ -209,7 +209,7 @@ import { useAppwrite } from "@appwrite.io/react"; const { client, account, tablesDB, storage, teams, ssr } = useAppwrite(); ``` -Returns the underlying provider context with every Appwrite Web SDK service instance bound to the configured client. Use it when you need direct access to a service the higher-level hooks do not wrap (databases, storage, messaging, realtime, and so on). +Returns the underlying provider context with every Appwrite Web SDK service instance bound to the configured client. Use it when you need direct access to a service the higher-level hooks do not wrap (`tablesDB`, `storage`, `messaging`, `realtime`, and so on). Returns: @@ -278,7 +278,7 @@ if (session) { ## Admin client {% #admin-client %} -For privileged operations (creating users, listing sessions, managing teams) call `createAdminClient` on the framework helper. Pass `apiKey` in the helper config to enable it, then call the method anywhere on the server. The returned object exposes every `node-appwrite` service: `account`, `users`, `databases`, `storage`, `teams`, `functions`, `messaging`, `tablesDB`, and more. +For privileged operations (creating users, listing sessions, managing teams) call `createAdminClient` on the framework helper. Pass `apiKey` in the helper config to enable it, then call the method anywhere on the server. The returned object exposes every `node-appwrite` service: `account`, `users`, `tablesDB`, `storage`, `teams`, `functions`, `messaging`, and more. ```ts import { createNextServerHelpers } from "@appwrite.io/react/server/next"; From 5f2c04359803a3bc5944557ddadf6db2d78cf8e5 Mon Sep 17 00:00:00 2001 From: adityaoberai Date: Sat, 6 Jun 2026 02:27:52 +0530 Subject: [PATCH 10/61] Restructure APIs docs and apply PR review feedback - Remove deprecated Scale plan from Billing (page, nav, card); redirect old platform path to Pro - Regroup Billing: move the payments page out of Plans into 'Manage billing' - Fold former API Integration content into the APIs section; drop the standalone section - Add an 'Events & Errors' subsection (events, webhooks, response codes, error handling) via URL-invisible route groups; leave REST/GraphQL/Realtime untouched - Move Release policy to Advanced - Repoint redirects and internal links; update STYLE.md - Add Sept 1, 2026 deprecation date to Dev keys note; fix malformed release-policy anchor Co-Authored-By: Claude Opus 4.8 (1M context) --- STYLE.md | 8 ++- src/redirects.json | 20 +++--- src/routes/docs/Sidebar.svelte | 29 +++++---- .../advanced/api-integration/+layout.svelte | 61 ------------------- .../advanced/api-integration/+page.markdoc | 43 ------------- .../docs/advanced/billing/+layout.svelte | 12 ++-- .../docs/advanced/billing/+page.markdoc | 20 +++--- .../advanced/billing/payments/+page.markdoc | 2 +- .../docs/advanced/billing/scale/+page.markdoc | 9 --- .../advanced/release-policy/+layout.svelte | 9 +++ .../release-policy/+page.markdoc | 2 +- .../security/audit-logs/+page.markdoc | 2 +- .../advanced/security/dev-keys/+page.markdoc | 2 +- .../production/debugging/+page.markdoc | 2 +- .../apis/(events-and-errors)/+layout.svelte | 43 +++++++++++++ .../error-handling/+page.markdoc | 2 +- .../(events-and-errors)}/events/+page.markdoc | 2 +- .../response-codes/+page.markdoc | 0 .../webhooks/+page.markdoc | 6 +- src/routes/docs/apis/realtime/+page.markdoc | 2 +- .../docs/apis/realtime/payload/+page.markdoc | 2 +- .../products/functions/execute/+page.markdoc | 4 +- .../functions/executions/+page.markdoc | 2 +- .../functions/functions/+page.markdoc | 2 +- src/routes/docs/references/+page.markdoc | 2 +- .../resources/webhooks/+page.markdoc | 4 +- 26 files changed, 119 insertions(+), 173 deletions(-) delete mode 100644 src/routes/docs/advanced/api-integration/+layout.svelte delete mode 100644 src/routes/docs/advanced/api-integration/+page.markdoc delete mode 100644 src/routes/docs/advanced/billing/scale/+page.markdoc create mode 100644 src/routes/docs/advanced/release-policy/+layout.svelte rename src/routes/docs/advanced/{api-integration => }/release-policy/+page.markdoc (99%) create mode 100644 src/routes/docs/apis/(events-and-errors)/+layout.svelte rename src/routes/docs/{advanced/api-integration => apis/(events-and-errors)}/error-handling/+page.markdoc (97%) rename src/routes/docs/{advanced/api-integration => apis/(events-and-errors)}/events/+page.markdoc (98%) rename src/routes/docs/{advanced/api-integration => apis/(events-and-errors)}/response-codes/+page.markdoc (100%) rename src/routes/docs/{advanced/api-integration => apis/(events-and-errors)}/webhooks/+page.markdoc (99%) diff --git a/STYLE.md b/STYLE.md index d731a6b549b..646bf44645b 100644 --- a/STYLE.md +++ b/STYLE.md @@ -48,6 +48,10 @@ APIs section: - [GraphQL](https://appwrite.io/docs/apis/graphql) - [REST](https://appwrite.io/docs/apis/rest) - [Realtime](https://appwrite.io/docs/apis/realtime) +- [Events](https://appwrite.io/docs/apis/events) +- [Webhooks](https://appwrite.io/docs/apis/webhooks) +- [Response codes](https://appwrite.io/docs/apis/response-codes) +- [Error handling](https://appwrite.io/docs/apis/error-handling) Tooling section: @@ -58,10 +62,10 @@ Tooling section: Advanced section: - [Billing](https://appwrite.io/docs/advanced/billing) -- [API integration](https://appwrite.io/docs/advanced/api-integration) - [Migrations](https://appwrite.io/docs/advanced/migrations) - [Self-hosting](https://appwrite.io/docs/advanced/self-hosting) - [Security](https://appwrite.io/docs/advanced/security) +- [Release policy](https://appwrite.io/docs/advanced/release-policy) Here's the intended purpose and structure of each section. @@ -215,7 +219,7 @@ Split content such that each piece makes sense without reading dependents or exp - [ ] Point Cloud to new version in [src/routes/docs/references/[version]/[platform]/[service]/+page.server.ts](src/routes/docs/references/[version]/[platform]/[service]/+page.server.ts) - [ ] Update install command in [/workspaces/website/src/routes/docs/advanced/self-hosting/+page.markdoc](/workspaces/website/src/routes/docs/advanced/self-hosting/+page.markdoc) - [ ] Update events [src/partials/[product]-events.md](src/partials/) -- [ ] Update response code [src/routes/docs/advanced/api-integration/response-codes/+page.markdoc](src/routes/docs/advanced/api-integration/response-codes/+page.markdoc) +- [ ] Update response code [src/routes/docs/apis/response-codes/+page.markdoc](src/routes/docs/apis/response-codes/+page.markdoc) - [ ] Bump latest SDK versions in SDKs page, quick start, and tutorials - [ ] Create new sections for new products - [ ] Create new concept and journey pages for new features diff --git a/src/redirects.json b/src/redirects.json index 592c185e006..bf25294a4f5 100644 --- a/src/redirects.json +++ b/src/redirects.json @@ -209,7 +209,7 @@ }, { "link": "/docs/events", - "redirect": "/docs/advanced/api-integration/events" + "redirect": "/docs/apis/events" }, { "link": "/docs/queries", @@ -221,7 +221,7 @@ }, { "link": "/docs/webhooks", - "redirect": "/docs/advanced/api-integration/webhooks" + "redirect": "/docs/apis/webhooks" }, { "link": "/docs/custom-domains", @@ -233,7 +233,7 @@ }, { "link": "/docs/response-codes", - "redirect": "/docs/advanced/api-integration/response-codes" + "redirect": "/docs/apis/response-codes" }, { "link": "/docs/rate-limits", @@ -934,7 +934,7 @@ }, { "link": "/docs/advanced/platform/scale", - "redirect": "/docs/advanced/billing/scale" + "redirect": "/docs/advanced/billing/pro" }, { "link": "/docs/advanced/platform/enterprise", @@ -982,23 +982,23 @@ }, { "link": "/docs/advanced/platform/events", - "redirect": "/docs/advanced/api-integration/events" + "redirect": "/docs/apis/events" }, { "link": "/docs/advanced/platform/webhooks", - "redirect": "/docs/advanced/api-integration/webhooks" + "redirect": "/docs/apis/webhooks" }, { "link": "/docs/advanced/platform/response-codes", - "redirect": "/docs/advanced/api-integration/response-codes" + "redirect": "/docs/apis/response-codes" }, { "link": "/docs/advanced/platform/error-handling", - "redirect": "/docs/advanced/api-integration/error-handling" + "redirect": "/docs/apis/error-handling" }, { "link": "/docs/advanced/platform/release-policy", - "redirect": "/docs/advanced/api-integration/release-policy" + "redirect": "/docs/advanced/release-policy" }, { "link": "/docs/advanced/platform/permissions", @@ -1038,6 +1038,6 @@ }, { "link": "/docs/advanced/integration", - "redirect": "/docs/advanced/api-integration" + "redirect": "/docs/apis/rest" } ] diff --git a/src/routes/docs/Sidebar.svelte b/src/routes/docs/Sidebar.svelte index aa4af364e4a..bdae94eeaa2 100644 --- a/src/routes/docs/Sidebar.svelte +++ b/src/routes/docs/Sidebar.svelte @@ -110,12 +110,6 @@ { label: 'APIS', items: [ - { - label: 'Realtime', - href: '/docs/apis/realtime', - icon: 'icon-clock', - isParent: true - }, { label: 'REST', href: '/docs/apis/rest', @@ -125,6 +119,18 @@ label: 'GraphQL', href: '/docs/apis/graphql', icon: 'icon-graphql' + }, + { + label: 'Realtime', + href: '/docs/apis/realtime', + icon: 'icon-clock', + isParent: true + }, + { + label: 'Events & Errors', + href: '/docs/apis/events', + icon: 'icon-switch-horizontal', + isParent: true } ] }, @@ -177,12 +183,6 @@ icon: 'icon-share', isParent: true }, - { - label: 'API Integration', - href: '/docs/advanced/api-integration', - icon: 'icon-switch-horizontal', - isParent: true - }, { label: 'Migrations', href: '/docs/advanced/migrations', @@ -200,6 +200,11 @@ href: '/docs/advanced/self-hosting', icon: 'icon-server', isParent: true + }, + { + label: 'Release policy', + href: '/docs/advanced/release-policy', + icon: 'icon-tag' } ] } diff --git a/src/routes/docs/advanced/api-integration/+layout.svelte b/src/routes/docs/advanced/api-integration/+layout.svelte deleted file mode 100644 index 419f18cda54..00000000000 --- a/src/routes/docs/advanced/api-integration/+layout.svelte +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - diff --git a/src/routes/docs/advanced/api-integration/+page.markdoc b/src/routes/docs/advanced/api-integration/+page.markdoc deleted file mode 100644 index 9419cab0efd..00000000000 --- a/src/routes/docs/advanced/api-integration/+page.markdoc +++ /dev/null @@ -1,43 +0,0 @@ ---- -layout: article -title: API integration -description: Integrate Appwrite with your apps using events and webhooks, and learn how Appwrite's APIs report response codes and errors. ---- - -Appwrite is designed to integrate with both your frontend and backend apps. Learn how to react to platform events, keep external systems in sync with webhooks, and handle the response codes and errors returned by Appwrite's APIs. - -# Events and webhooks {% #events-and-webhooks %} - -React to events that occur across your Appwrite project and notify external systems. - -{% cards %} -{% cards_item href="/docs/advanced/api-integration/events" title="Events" %} -Appwrite allows you to react to events that occur on the platform. -{% /cards_item %} - -{% cards_item href="/docs/advanced/api-integration/webhooks" title="Webhooks" %} -Use webhooks to update backend integrations about Appwrite events. -{% /cards_item %} -{% /cards %} - -# Error reference {% #error-reference %} - -Understand how Appwrite's APIs report success and failure, and how to handle errors gracefully. - -{% cards %} -{% cards_item href="/docs/advanced/api-integration/response-codes" title="Response codes" %} -Learn about response codes and errors returned by Appwrite APIs. -{% /cards_item %} - -{% cards_item href="/docs/advanced/api-integration/error-handling" title="Error handling" %} -Best practices for handling Appwrite errors in your applications. -{% /cards_item %} -{% /cards %} - -# Policies {% #policies %} - -{% cards %} -{% cards_item href="/docs/advanced/api-integration/release-policy" title="Release policy" %} -Understand how Appwrite releases and versions its platforms and APIs. -{% /cards_item %} -{% /cards %} diff --git a/src/routes/docs/advanced/billing/+layout.svelte b/src/routes/docs/advanced/billing/+layout.svelte index 584592ca24e..bfeff43e6e9 100644 --- a/src/routes/docs/advanced/billing/+layout.svelte +++ b/src/routes/docs/advanced/billing/+layout.svelte @@ -14,16 +14,16 @@ { label: 'Overview', href: '/docs/advanced/billing' + }, + { + label: 'Manage billing', + href: '/docs/advanced/billing/payments' } ] }, { label: 'Plans', items: [ - { - label: 'Billing', - href: '/docs/advanced/billing/payments' - }, { label: 'Free', href: '/docs/advanced/billing/free' @@ -32,10 +32,6 @@ label: 'Pro', href: '/docs/advanced/billing/pro' }, - { - label: 'Scale', - href: '/docs/advanced/billing/scale' - }, { label: 'Enterprise', href: '/docs/advanced/billing/enterprise' diff --git a/src/routes/docs/advanced/billing/+page.markdoc b/src/routes/docs/advanced/billing/+page.markdoc index 4aa6db90442..1592f0259e8 100644 --- a/src/routes/docs/advanced/billing/+page.markdoc +++ b/src/routes/docs/advanced/billing/+page.markdoc @@ -4,17 +4,23 @@ title: Billing description: Understand Appwrite's plans, add-ons, service level agreements, and billing policies. --- -Learn which plan best suits your organization, explore optional add-ons, and understand Appwrite's service level agreements and billing policies. +Learn how to manage billing for your organization, find the plan that best suits your needs, explore optional add-ons, and understand Appwrite's service level agreements and billing policies. -# Plans {% #plans %} +# Manage billing {% #manage-billing %} -Learn which plan best suits your organization and how to manage billing. +Configure your organization's plan, payment methods, and spending controls. {% cards %} -{% cards_item href="/docs/advanced/billing/payments" title="Billing" %} -Learn to manage your billing information. +{% cards_item href="/docs/advanced/billing/payments" title="Manage billing" %} +Manage your plan, billing periods, payment methods, budget caps, and invoices. {% /cards_item %} +{% /cards %} + +# Plans {% #plans %} +Learn which plan best suits your organization. + +{% cards %} {% cards_item href="/docs/advanced/billing/free" title="Free" %} Learn about Appwrite Free plan. Free plan for hobby projects and learners. {% /cards_item %} @@ -23,10 +29,6 @@ Learn about Appwrite Free plan. Free plan for hobby projects and learners. Learn about Appwrite Pro, for growing organizations that need to scale. {% /cards_item %} -{% cards_item href="/docs/advanced/billing/scale" title="Scale" %} -Learn about Appwrite Scale, for teams and agencies scaling their applications. -{% /cards_item %} - {% cards_item href="/docs/advanced/billing/enterprise" title="Enterprise" %} Learn about Appwrite Enterprise, for large organizations with advanced needs. {% /cards_item %} diff --git a/src/routes/docs/advanced/billing/payments/+page.markdoc b/src/routes/docs/advanced/billing/payments/+page.markdoc index 43f8c77a578..92e27708111 100644 --- a/src/routes/docs/advanced/billing/payments/+page.markdoc +++ b/src/routes/docs/advanced/billing/payments/+page.markdoc @@ -1,6 +1,6 @@ --- layout: article -title: Billing +title: Manage billing description: Understand Appwrite's billing features, like budget caps, billing periods, taxes, and more. --- diff --git a/src/routes/docs/advanced/billing/scale/+page.markdoc b/src/routes/docs/advanced/billing/scale/+page.markdoc deleted file mode 100644 index 3703eac6f6d..00000000000 --- a/src/routes/docs/advanced/billing/scale/+page.markdoc +++ /dev/null @@ -1,9 +0,0 @@ ---- -layout: article -title: Scale -description: Appwrite's Scale plan fully supports scaling your application. ---- - -Appwrite's Scale plan is designed for growing development teams and agencies with many organizational members and large projects. -The plan offers unlimited seats across your organization and dedicated resources per project. -Scale plan organizations will receive additional compliance measures, organization roles, and dedicated support. diff --git a/src/routes/docs/advanced/release-policy/+layout.svelte b/src/routes/docs/advanced/release-policy/+layout.svelte new file mode 100644 index 00000000000..93e22c8cebf --- /dev/null +++ b/src/routes/docs/advanced/release-policy/+layout.svelte @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/routes/docs/advanced/api-integration/release-policy/+page.markdoc b/src/routes/docs/advanced/release-policy/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/api-integration/release-policy/+page.markdoc rename to src/routes/docs/advanced/release-policy/+page.markdoc index 3c1c9efbbe2..c39ac872fa6 100644 --- a/src/routes/docs/advanced/api-integration/release-policy/+page.markdoc +++ b/src/routes/docs/advanced/release-policy/+page.markdoc @@ -79,7 +79,7 @@ Self-hosted versions of Appwrite will receive continued support for the latest m If you need **extended support** for older versions of Appwrite, [contact us](/contact-us) for more information. -# SDK versioning {% #sdk-verversioningsions %} +# SDK versioning {% #sdk-versioning %} For our different SDKs, we follow the Semantic Versioning (semver) protocol to assign versions to our releases. This means that we assign version numbers using a three-part system: major, minor, and patch. The major version changes when we make significant changes to our API or product, which may require significant changes to developers' code. The minor version changes when we add new features or functionality that do not significantly impact developers' systems. Finally, the patch version changes when we make bug fixes or minor improvements. diff --git a/src/routes/docs/advanced/security/audit-logs/+page.markdoc b/src/routes/docs/advanced/security/audit-logs/+page.markdoc index b35cc10c2cb..4499f50f9a8 100644 --- a/src/routes/docs/advanced/security/audit-logs/+page.markdoc +++ b/src/routes/docs/advanced/security/audit-logs/+page.markdoc @@ -36,7 +36,7 @@ Each entry describes an event. - Name of the user that performed the event. --- - Event -- The name of the [event](/docs/advanced/api-integration/events). +- The name of the [event](/docs/apis/events). --- - Location - The physical of the user when they performed the action. diff --git a/src/routes/docs/advanced/security/dev-keys/+page.markdoc b/src/routes/docs/advanced/security/dev-keys/+page.markdoc index bb3ee0e89f4..5ebeec94b2a 100644 --- a/src/routes/docs/advanced/security/dev-keys/+page.markdoc +++ b/src/routes/docs/advanced/security/dev-keys/+page.markdoc @@ -5,7 +5,7 @@ description: Bypass Appwrite rate limits and CORS errors in your development env --- {% info title="Deprecation notice" %} -Dev keys are going to be deprecated soon. We recommend planning your migration away from dev keys ahead of time. +Dev keys are going to be deprecated on September 1, 2026. We recommend planning your migration away from dev keys ahead of time. {% /info %} Dev keys are secrets used by Appwrite [Client SDKs](/docs/sdks#client) to avoid abuse limits in testing. They are meant to be used specifically in development environments, where they hold several developer experience-related benefits: diff --git a/src/routes/docs/advanced/self-hosting/production/debugging/+page.markdoc b/src/routes/docs/advanced/self-hosting/production/debugging/+page.markdoc index 6f6360ca299..aedbf6005c3 100644 --- a/src/routes/docs/advanced/self-hosting/production/debugging/+page.markdoc +++ b/src/routes/docs/advanced/self-hosting/production/debugging/+page.markdoc @@ -34,7 +34,7 @@ docker logs [CONTAINER-ID] Appwrite uses conventional HTTP response codes to indicate the success or failure of an API request. In general: Codes in the 2xx range indicate success. Codes in the 4xx range indicate an error that failed given the information provided (e.g., a required parameter was omitted, invalid input, etc.). Codes in the 5xx range indicate an error with the Appwrite server, but these are rare. -{% arrow_link href="/docs/advanced/api-integration/response-codes" %} +{% arrow_link href="/docs/apis/response-codes" %} Learn more about Appwrite status codes {% /arrow_link %} diff --git a/src/routes/docs/apis/(events-and-errors)/+layout.svelte b/src/routes/docs/apis/(events-and-errors)/+layout.svelte new file mode 100644 index 00000000000..622a4beb607 --- /dev/null +++ b/src/routes/docs/apis/(events-and-errors)/+layout.svelte @@ -0,0 +1,43 @@ + + + + + + diff --git a/src/routes/docs/advanced/api-integration/error-handling/+page.markdoc b/src/routes/docs/apis/(events-and-errors)/error-handling/+page.markdoc similarity index 97% rename from src/routes/docs/advanced/api-integration/error-handling/+page.markdoc rename to src/routes/docs/apis/(events-and-errors)/error-handling/+page.markdoc index fabb96d3f55..b1f7fb2cff9 100644 --- a/src/routes/docs/advanced/api-integration/error-handling/+page.markdoc +++ b/src/routes/docs/apis/(events-and-errors)/error-handling/+page.markdoc @@ -53,7 +53,7 @@ Here are some examples of how you might map Appwrite error types to user-friendl # Complete list of error types -Appwrite provides a comprehensive list of error types organized by category. For a complete reference, see the [Response codes](/docs/advanced/api-integration/response-codes#error-types) documentation. +Appwrite provides a comprehensive list of error types organized by category. For a complete reference, see the [Response codes](/docs/apis/response-codes#error-types) documentation. # Recommended practices diff --git a/src/routes/docs/advanced/api-integration/events/+page.markdoc b/src/routes/docs/apis/(events-and-errors)/events/+page.markdoc similarity index 98% rename from src/routes/docs/advanced/api-integration/events/+page.markdoc rename to src/routes/docs/apis/(events-and-errors)/events/+page.markdoc index b79bfb922d1..a4604f5847f 100644 --- a/src/routes/docs/advanced/api-integration/events/+page.markdoc +++ b/src/routes/docs/apis/(events-and-errors)/events/+page.markdoc @@ -6,7 +6,7 @@ description: Harness the power of events in Appwrite. Explore event-driven archi Appwrite provides a variety of events that allows your application to react to changes as they happen. An event will fire when a change occurs in your Appwrite project, like when a new user registers or a new file is uploaded to Appwrite. -You can subscribe to these events with Appwrite [Functions](/docs/products/functions), [Realtime](/docs/apis/realtime), or [Webhooks](/docs/advanced/api-integration/webhooks). +You can subscribe to these events with Appwrite [Functions](/docs/products/functions), [Realtime](/docs/apis/realtime), or [Webhooks](/docs/apis/webhooks). You can subscribe to events for specific resources using their ID or subscribe to changes of all resources of the same type by using a wildcard character * instead of an ID. You can also filter for events of specific actions like create, update, upsert, or delete. diff --git a/src/routes/docs/advanced/api-integration/response-codes/+page.markdoc b/src/routes/docs/apis/(events-and-errors)/response-codes/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/api-integration/response-codes/+page.markdoc rename to src/routes/docs/apis/(events-and-errors)/response-codes/+page.markdoc diff --git a/src/routes/docs/advanced/api-integration/webhooks/+page.markdoc b/src/routes/docs/apis/(events-and-errors)/webhooks/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/api-integration/webhooks/+page.markdoc rename to src/routes/docs/apis/(events-and-errors)/webhooks/+page.markdoc index b194dafab41..bd9b1e2b992 100644 --- a/src/routes/docs/advanced/api-integration/webhooks/+page.markdoc +++ b/src/routes/docs/apis/(events-and-errors)/webhooks/+page.markdoc @@ -1474,7 +1474,7 @@ async fn main() -> Result<(), Box> { # Payload {% #payload %} -Each event type has a specific payload format with the relevant event information. All event payloads mirror the payloads for the API payload which parallel to the [event types](/docs/advanced/api-integration/events). +Each event type has a specific payload format with the relevant event information. All event payloads mirror the payloads for the API payload which parallel to the [event types](/docs/apis/events). # Headers {% #headers %} @@ -1484,7 +1484,7 @@ HTTP requests made to your webhook's configured URL endpoint will contain severa |--------|-------------| | X-Appwrite-Webhook-Id | The ID of the Webhook who triggered the event. | | X-Appwrite-Webhook-Events | Names of the events that triggered this delivery. | -| X-Appwrite-Webhook-Name | Name of the webhook as specified in your app settings and [events list](/docs/advanced/api-integration/events). | +| X-Appwrite-Webhook-Name | Name of the webhook as specified in your app settings and [events list](/docs/apis/events). | | X-Appwrite-Webhook-User-Id | The user ID of the user who triggered the event. Returns an empty string if an API key triggered the event. Note that events like `account.create` or `account.sessions.create` are performed by guest users and will not return any user ID. If you still need the user ID for these events, you can find it in the event payload. | | X-Appwrite-Webhook-Project-Id | The ID of the project who owns the Webhook and API call. | | X-Appwrite-Webhook-Signature | The HMAC-SHA1 signature of the payload. This is used to verify the authenticity of the payload. | @@ -1704,4 +1704,4 @@ You can specify one or many events to subscribe to with webhooks. {% /accordion_item %} {% /accordion %} -[Learn more about events](/docs/advanced/api-integration/events) +[Learn more about events](/docs/apis/events) diff --git a/src/routes/docs/apis/realtime/+page.markdoc b/src/routes/docs/apis/realtime/+page.markdoc index cbd5b9218f7..f57020ef502 100644 --- a/src/routes/docs/apis/realtime/+page.markdoc +++ b/src/routes/docs/apis/realtime/+page.markdoc @@ -116,7 +116,7 @@ To subscribe to updates from different Appwrite resources, you need to specify o If you subscribe to a channel, you will receive callbacks for a variety of events related to the channel. The events column in the callback can be used to filter and respond to specific events in a channel. -[View a list of all available events](/docs/advanced/api-integration/events). +[View a list of all available events](/docs/apis/events). {% info title="Permissions" %} All subscriptions are secured by the [permissions system](/docs/advanced/security/permissions) offered by Appwrite, meaning a user will only receive updates to resources they have permission to access. diff --git a/src/routes/docs/apis/realtime/payload/+page.markdoc b/src/routes/docs/apis/realtime/payload/+page.markdoc index b6a70760351..72d37f463cf 100644 --- a/src/routes/docs/apis/realtime/payload/+page.markdoc +++ b/src/routes/docs/apis/realtime/payload/+page.markdoc @@ -17,7 +17,7 @@ The payload from the subscription will contain the following properties: --- * events * string[] -* The [Appwrite events](/docs/advanced/api-integration/events) that triggered this update. +* The [Appwrite events](/docs/apis/events) that triggered this update. --- * channels * string[] diff --git a/src/routes/docs/products/functions/execute/+page.markdoc b/src/routes/docs/products/functions/execute/+page.markdoc index c1a46689b46..326c5be60c3 100644 --- a/src/routes/docs/products/functions/execute/+page.markdoc +++ b/src/routes/docs/products/functions/execute/+page.markdoc @@ -34,7 +34,7 @@ Asynchronous executions are added to a queue and processed by the function worke Asynchronous executions are created via: - The [Create execution](/docs/references/cloud/client-web/functions#createExecution) endpoint where the `async` parameter is `true` -- Event triggers (when functions are triggered by [platform events](/docs/advanced/api-integration/events)) +- Event triggers (when functions are triggered by [platform events](/docs/apis/events)) - Scheduled executions (cron jobs or delayed executions) Asynchronous executions: @@ -524,7 +524,7 @@ Changes in Appwrite emit events. You can configure Functions to be executed in r 5. Be careful to avoid selecting events that can be caused by the function itself. This can cause the function to trigger its own execution, resulting in infinite recursions. In these executions, the event that triggered the function will be passed as the header `x-appwrite-event` to the function. -The `request.body` parameter will contain the event data. [Learn more about events](/docs/advanced/api-integration/events). +The `request.body` parameter will contain the event data. [Learn more about events](/docs/apis/events). You can use one of the following events. {% accordion %} diff --git a/src/routes/docs/products/functions/executions/+page.markdoc b/src/routes/docs/products/functions/executions/+page.markdoc index dcd59f80fdc..f3a1e2c000b 100644 --- a/src/routes/docs/products/functions/executions/+page.markdoc +++ b/src/routes/docs/products/functions/executions/+page.markdoc @@ -27,7 +27,7 @@ Here's the information shown on this table. - Timestamp of when the execution was created --- - Trigger -- The [platform event](/docs/advanced/api-integration/events) that triggered the execution +- The [platform event](/docs/apis/events) that triggered the execution --- - Method - The HTTP method used to create the execution diff --git a/src/routes/docs/products/functions/functions/+page.markdoc b/src/routes/docs/products/functions/functions/+page.markdoc index 5b38658ffd2..d8bdced0bb9 100644 --- a/src/routes/docs/products/functions/functions/+page.markdoc +++ b/src/routes/docs/products/functions/functions/+page.markdoc @@ -139,7 +139,7 @@ If this is left empty, no user can execute your function. Server SDKs, scheduled executions, and event function triggers don't require permissions to execute a function. ## Events{% #events %} -Functions can be triggered by [platform events](/docs/advanced/api-integration/events) which reflect changes +Functions can be triggered by [platform events](/docs/apis/events) which reflect changes that occur in your Appwrite project. You can configure events triggers by navigating to your function > **Settings** > **Events**. diff --git a/src/routes/docs/references/+page.markdoc b/src/routes/docs/references/+page.markdoc index a14c1bb4a4f..e3095b963fd 100644 --- a/src/routes/docs/references/+page.markdoc +++ b/src/routes/docs/references/+page.markdoc @@ -70,4 +70,4 @@ Track which signed-in users are active right now and broadcast their status in r ## Error handling {% #error-handling %} -When building with Appwrite, implement proper error handling to provide user-friendly messages instead of exposing raw error responses. For implementation details and best practices, refer to our [Error handling guide](/docs/advanced/api-integration/error-handling) and [Response codes](/docs/advanced/api-integration/response-codes#error-types) documentation. +When building with Appwrite, implement proper error handling to provide user-friendly messages instead of exposing raw error responses. For implementation details and best practices, refer to our [Error handling guide](/docs/apis/error-handling) and [Response codes](/docs/apis/response-codes#error-types) documentation. diff --git a/src/routes/docs/tooling/terraform/resources/webhooks/+page.markdoc b/src/routes/docs/tooling/terraform/resources/webhooks/+page.markdoc index 5905f7827e4..65dd1e2cda9 100644 --- a/src/routes/docs/tooling/terraform/resources/webhooks/+page.markdoc +++ b/src/routes/docs/tooling/terraform/resources/webhooks/+page.markdoc @@ -40,7 +40,7 @@ resource "appwrite_webhook" "authenticated" { } ``` -Use the read-only **`secret`** attribute when configuring **signature verification** for payloads Appwrite sends to your URL (see [Webhooks](/docs/advanced/api-integration/webhooks) in the platform docs). +Use the read-only **`secret`** attribute when configuring **signature verification** for payloads Appwrite sends to your URL (see [Webhooks](/docs/apis/webhooks) in the platform docs). # Data sources {% #data-sources %} @@ -61,4 +61,4 @@ See the [Terraform Registry](https://registry.terraform.io/providers/appwrite/ap # Related {% #related %} - [Configuration](/docs/tooling/terraform/provider): authentication and endpoints -- [Webhooks](/docs/advanced/api-integration/webhooks): event delivery, headers, and signatures +- [Webhooks](/docs/apis/webhooks): event delivery, headers, and signatures From 475e7af563a96d3babb2e0683769f2c3f575305e Mon Sep 17 00:00:00 2001 From: adityaoberai Date: Fri, 12 Jun 2026 05:13:15 +0530 Subject: [PATCH 11/61] APIs docs overview page + layout update --- src/routes/docs/Sidebar.svelte | 5 +++ .../apis/(events-and-errors)/+layout.svelte | 2 +- .../docs/apis/(overview)/+layout.svelte | 9 ++++ src/routes/docs/apis/(overview)/+page.markdoc | 44 +++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/routes/docs/apis/(overview)/+layout.svelte create mode 100644 src/routes/docs/apis/(overview)/+page.markdoc diff --git a/src/routes/docs/Sidebar.svelte b/src/routes/docs/Sidebar.svelte index bdae94eeaa2..11879d1300e 100644 --- a/src/routes/docs/Sidebar.svelte +++ b/src/routes/docs/Sidebar.svelte @@ -110,6 +110,11 @@ { label: 'APIS', items: [ + { + label: 'Overview', + href: '/docs/apis', + icon: 'icon-view-grid' + }, { label: 'REST', href: '/docs/apis/rest', diff --git a/src/routes/docs/apis/(events-and-errors)/+layout.svelte b/src/routes/docs/apis/(events-and-errors)/+layout.svelte index 622a4beb607..e4a6ed85ba1 100644 --- a/src/routes/docs/apis/(events-and-errors)/+layout.svelte +++ b/src/routes/docs/apis/(events-and-errors)/+layout.svelte @@ -22,7 +22,7 @@ ] }, { - label: 'Errors', + label: 'Responses & errors', items: [ { label: 'Response codes', diff --git a/src/routes/docs/apis/(overview)/+layout.svelte b/src/routes/docs/apis/(overview)/+layout.svelte new file mode 100644 index 00000000000..93e22c8cebf --- /dev/null +++ b/src/routes/docs/apis/(overview)/+layout.svelte @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/routes/docs/apis/(overview)/+page.markdoc b/src/routes/docs/apis/(overview)/+page.markdoc new file mode 100644 index 00000000000..919184403dd --- /dev/null +++ b/src/routes/docs/apis/(overview)/+page.markdoc @@ -0,0 +1,44 @@ +--- +layout: article +title: APIs +description: Explore the ways to talk to Appwrite. Access every service through the REST and GraphQL APIs, subscribe to changes in Realtime, and react to events with webhooks. +--- + +Every Appwrite service is available through a consistent set of APIs. You can call them directly over [REST](/docs/apis/rest) or [GraphQL](/docs/apis/graphql), subscribe to changes in [Realtime](/docs/apis/realtime), or react to changes using [events](/docs/apis/events) and [webhooks](/docs/apis/webhooks). + +Most applications don't call these APIs by hand. Instead, use one of the official [SDKs](/docs/sdks), which wrap every endpoint for your language and platform, and browse the [API reference](/docs/references) for the full list of services and methods. The pages below describe the underlying protocols and conventions for when you need to integrate directly. + +# Protocols {% #protocols %} + +Choose the protocol that fits your use case. REST and GraphQL cover the same endpoints, while Realtime delivers updates as they happen. + +{% cards %} +{% cards_item href="/docs/apis/rest" title="REST" %} +Access every Appwrite endpoint over HTTP without an SDK, including authentication, file uploads, queries, and permissions. +{% /cards_item %} +{% cards_item href="/docs/apis/graphql" title="GraphQL" %} +Query and mutate your data through a single GraphQL endpoint. +{% /cards_item %} +{% cards_item href="/docs/apis/realtime" title="Realtime" %} +Subscribe to channels and receive updates over WebSockets the moment your data changes. +{% /cards_item %} +{% /cards %} + +# Events & errors {% #events-and-errors %} + +React to changes across your project and understand the responses Appwrite returns. + +{% cards %} +{% cards_item href="/docs/apis/events" title="Events" %} +The full list of events Appwrite emits so you can react to changes across your project. +{% /cards_item %} +{% cards_item href="/docs/apis/webhooks" title="Webhooks" %} +Trigger external workflows by delivering events to your own HTTP endpoints. +{% /cards_item %} +{% cards_item href="/docs/apis/response-codes" title="Response codes" %} +The HTTP status codes and error types returned by the Appwrite APIs. +{% /cards_item %} +{% cards_item href="/docs/apis/error-handling" title="Error handling" %} +Patterns for catching and handling errors gracefully in your application. +{% /cards_item %} +{% /cards %} From b16455f624ab451bd630fee311fecd73127d01be Mon Sep 17 00:00:00 2001 From: adityaoberai Date: Fri, 12 Jun 2026 05:19:17 +0530 Subject: [PATCH 12/61] Remove outdated notes --- .../advanced/billing/database-reads-and-writes/+page.markdoc | 3 --- .../docs/advanced/billing/image-transformations/+page.markdoc | 4 ---- src/routes/docs/advanced/billing/phone-otp/+page.markdoc | 4 ---- 3 files changed, 11 deletions(-) diff --git a/src/routes/docs/advanced/billing/database-reads-and-writes/+page.markdoc b/src/routes/docs/advanced/billing/database-reads-and-writes/+page.markdoc index a01378c52fc..c33120354ec 100644 --- a/src/routes/docs/advanced/billing/database-reads-and-writes/+page.markdoc +++ b/src/routes/docs/advanced/billing/database-reads-and-writes/+page.markdoc @@ -3,9 +3,6 @@ layout: article title: Database Reads and Writes description: Learn how Appwrite handles database reads and writes and their associated costs. --- -{% info title="Note" %} -Updated pricing will take effect on April 10th, 2025. Check out this [blog post](/blog/post/announcing-database-reads-and-writes-pricing) for more information. -{% /info %} Appwrite provides powerful database capabilities through its [Database API](/docs/products/databases), allowing you to perform read and write operations across your application data. Understanding how these operations are counted and billed is essential for planning your application's scalability. diff --git a/src/routes/docs/advanced/billing/image-transformations/+page.markdoc b/src/routes/docs/advanced/billing/image-transformations/+page.markdoc index e789d372c29..80e219b45ab 100644 --- a/src/routes/docs/advanced/billing/image-transformations/+page.markdoc +++ b/src/routes/docs/advanced/billing/image-transformations/+page.markdoc @@ -4,10 +4,6 @@ title: Image Transformations description: Learn how to transform images using Appwrite's storage API. --- -{% info title="Note" %} -Changes will take effect on April 1st, 2025. Check out this [blog post](/blog/post/announcing-image-transformations-pricing) for more information. -{% /info %} - Appwrite enables the transformation of images before retrieval using the [getFilePreview](/docs/references/cloud/client-web/storage#getFilePreview) endpoint. This functionality supports resizing images by width and height, adjusting quality, and applying filters such as opacity, border colour, border radius, and more. ### Origin Image diff --git a/src/routes/docs/advanced/billing/phone-otp/+page.markdoc b/src/routes/docs/advanced/billing/phone-otp/+page.markdoc index 620464cca2b..c7449377750 100644 --- a/src/routes/docs/advanced/billing/phone-otp/+page.markdoc +++ b/src/routes/docs/advanced/billing/phone-otp/+page.markdoc @@ -4,10 +4,6 @@ title: Phone OTP description: Learn how Appwrite handles SMS-based OTP authentication for secure user verification. --- -{% info title="Note" %} -Changes will take effect on February 10th, 2025. Check out this [blog post](https://appwrite.io/blog/post/announcing-phone-OTP-pricing) for more information. -{% /info %} - Appwrite supports SMS-based OTP (One-Time Password) authentication to provide secure and reliable user verification. This feature enhances your app's security by adding an extra layer of authentication. # Free testing {% #free-testing %} From 381e31b10fde16bed7b72a41f0b82f01840211c7 Mon Sep 17 00:00:00 2001 From: adityaoberai Date: Fri, 12 Jun 2026 05:24:38 +0530 Subject: [PATCH 13/61] Improve API docs overview structuring --- src/routes/docs/apis/(overview)/+page.markdoc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/routes/docs/apis/(overview)/+page.markdoc b/src/routes/docs/apis/(overview)/+page.markdoc index 919184403dd..85ebdb3b1e7 100644 --- a/src/routes/docs/apis/(overview)/+page.markdoc +++ b/src/routes/docs/apis/(overview)/+page.markdoc @@ -24,9 +24,9 @@ Subscribe to channels and receive updates over WebSockets the moment your data c {% /cards_item %} {% /cards %} -# Events & errors {% #events-and-errors %} +# Event-driven workflows {% #events-and-errors %} -React to changes across your project and understand the responses Appwrite returns. +React to project changes with events emitted by Appwrite and webhooks delivered to your own endpoints. {% cards %} {% cards_item href="/docs/apis/events" title="Events" %} @@ -35,6 +35,13 @@ The full list of events Appwrite emits so you can react to changes across your p {% cards_item href="/docs/apis/webhooks" title="Webhooks" %} Trigger external workflows by delivering events to your own HTTP endpoints. {% /cards_item %} +{% /cards %} + +# API responses and errors {% #api-responses-and-errors %} + +Understand the responses Appwrite returns and build error handling that helps your application recover gracefully. + +{% cards %} {% cards_item href="/docs/apis/response-codes" title="Response codes" %} The HTTP status codes and error types returned by the Appwrite APIs. {% /cards_item %} From dc5bb922daa4854418b6a5090137c4381c8c60ac Mon Sep 17 00:00:00 2001 From: adityaoberai Date: Fri, 12 Jun 2026 05:29:24 +0530 Subject: [PATCH 14/61] Add new VCS variables --- src/partials/functions-env-vars.md | 43 ++++++++++++++++++++---------- src/partials/sites-env-vars.md | 39 ++++++++++++++++++++------- 2 files changed, 58 insertions(+), 24 deletions(-) diff --git a/src/partials/functions-env-vars.md b/src/partials/functions-env-vars.md index 1c5bcde396a..1be0e446f26 100644 --- a/src/partials/functions-env-vars.md +++ b/src/partials/functions-env-vars.md @@ -1,14 +1,29 @@ -| Variable | Description | Available at Build and/or Run Time | -| ----------------------------------- | ---------------------------------------------------------- | ---------------------------------- | -| `APPWRITE_FUNCTION_API_ENDPOINT` | The API endpoint of the running function | Both | -| `APPWRITE_VERSION` | The Appwrite version used to run the function | Both | -| `APPWRITE_REGION` | The region where the function will run from | Both | -| `APPWRITE_FUNCTION_API_KEY` | The function API key used for server authentication | Build time | -| `APPWRITE_FUNCTION_ID` | The ID of the running function | Both | -| `APPWRITE_FUNCTION_NAME` | The name of the running function | Both | -| `APPWRITE_FUNCTION_DEPLOYMENT` | The deployment ID of the running function | Both | -| `APPWRITE_FUNCTION_PROJECT_ID` | The project ID of the running function | Both | -| `APPWRITE_FUNCTION_RUNTIME_NAME` | The runtime of the running function | Both | -| `APPWRITE_FUNCTION_RUNTIME_VERSION` | The runtime version of the running function | Both | -| `APPWRITE_FUNCTION_CPUS` | The CPU (runtime) specification of the running function | Both | -| `APPWRITE_FUNCTION_MEMORY` | The memory (runtime) specification of the running function | Both | +| Variable | Description | Available at Build and/or Run Time | +| -------------------------------------- | ------------------------------------------------------------- | ---------------------------------- | +| `APPWRITE_FUNCTION_API_ENDPOINT` | The API endpoint of the running function | Both | +| `APPWRITE_VERSION` | The Appwrite version used to run the function | Both | +| `APPWRITE_REGION` | The region where the function will run from | Both | +| `APPWRITE_DEPLOYMENT_TYPE` | The deployment source type, such as `manual`, `cli`, or `vcs` | Both | +| `APPWRITE_FUNCTION_API_KEY` | The function API key used for server authentication | Build time | +| `APPWRITE_FUNCTION_ID` | The ID of the running function | Both | +| `APPWRITE_FUNCTION_NAME` | The name of the running function | Both | +| `APPWRITE_FUNCTION_DEPLOYMENT` | The deployment ID of the running function | Both | +| `APPWRITE_FUNCTION_PROJECT_ID` | The project ID of the running function | Both | +| `APPWRITE_FUNCTION_RUNTIME_NAME` | The runtime of the running function | Both | +| `APPWRITE_FUNCTION_RUNTIME_VERSION` | The runtime version of the running function | Both | +| `APPWRITE_FUNCTION_CPUS` | The CPU (runtime) specification of the running function | Both | +| `APPWRITE_FUNCTION_MEMORY` | The memory (runtime) specification of the running function | Both | +| `APPWRITE_VCS_REPOSITORY_ID` | The provider repository ID for VCS deployments | Both | +| `APPWRITE_VCS_REPOSITORY_NAME` | The provider repository name for VCS deployments | Both | +| `APPWRITE_VCS_REPOSITORY_OWNER` | The owner of the provider repository | Both | +| `APPWRITE_VCS_REPOSITORY_URL` | The URL of the provider repository | Both | +| `APPWRITE_VCS_REPOSITORY_BRANCH` | The branch used for the VCS deployment | Both | +| `APPWRITE_VCS_REPOSITORY_BRANCH_URL` | The URL of the branch used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_HASH` | The commit hash used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_MESSAGE` | The commit message used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_URL` | The URL of the commit used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_AUTHOR_NAME` | The name of the VCS commit author | Both | +| `APPWRITE_VCS_COMMIT_AUTHOR_URL` | The URL of the VCS commit author | Both | +| `APPWRITE_VCS_ROOT_DIRECTORY` | The root directory configured for the VCS deployment | Both | + +VCS metadata variables are populated for Git deployments. For manual and CLI deployments, VCS fields may be empty. diff --git a/src/partials/sites-env-vars.md b/src/partials/sites-env-vars.md index 906c9f246ae..eef8cbcefae 100644 --- a/src/partials/sites-env-vars.md +++ b/src/partials/sites-env-vars.md @@ -1,10 +1,29 @@ -| Variable | Description | Available at Build and/or Run Time | -| ------------------------------- | ------------------------------------------------------- | ---------------------------------- | -| `APPWRITE_SITE_API_ENDPOINT` | The API endpoint of the running site | Both | -| `APPWRITE_SITE_NAME` | The name of the running site. | Both | -| `APPWRITE_SITE_DEPLOYMENT` | The deployment ID of the running sites. | Both | -| `APPWRITE_SITE_PROJECT_ID` | The project ID of the running site. | Both | -| `APPWRITE_SITE_RUNTIME_NAME` | The runtime name of the running site. | Both | -| `APPWRITE_SITE_RUNTIME_VERSION` | The runtime version of the running site. | Both | -| `APPWRITE_SITE_CPUS` | The CPU (runtime) specification of the running site. | Both | -| `APPWRITE_SITE_MEMORY` | The memory (runtime) specification of the running site. | Both | +| Variable | Description | Available at Build and/or Run Time | +| ------------------------------------ | ------------------------------------------------------------- | ---------------------------------- | +| `APPWRITE_SITE_API_ENDPOINT` | The API endpoint of the running site | Both | +| `APPWRITE_VERSION` | The Appwrite version used to run the site | Both | +| `APPWRITE_REGION` | The region where the site will run from | Both | +| `APPWRITE_DEPLOYMENT_TYPE` | The deployment source type, such as `manual`, `cli`, or `vcs` | Both | +| `APPWRITE_SITE_API_KEY` | The site API key used for server authentication | Build time | +| `APPWRITE_SITE_ID` | The ID of the running site | Both | +| `APPWRITE_SITE_NAME` | The name of the running site | Both | +| `APPWRITE_SITE_DEPLOYMENT` | The deployment ID of the running site | Both | +| `APPWRITE_SITE_PROJECT_ID` | The project ID of the running site | Both | +| `APPWRITE_SITE_RUNTIME_NAME` | The runtime name of the running site | Both | +| `APPWRITE_SITE_RUNTIME_VERSION` | The runtime version of the running site | Both | +| `APPWRITE_SITE_CPUS` | The CPU (runtime) specification of the running site | Both | +| `APPWRITE_SITE_MEMORY` | The memory (runtime) specification of the running site | Both | +| `APPWRITE_VCS_REPOSITORY_ID` | The provider repository ID for VCS deployments | Both | +| `APPWRITE_VCS_REPOSITORY_NAME` | The provider repository name for VCS deployments | Both | +| `APPWRITE_VCS_REPOSITORY_OWNER` | The owner of the provider repository | Both | +| `APPWRITE_VCS_REPOSITORY_URL` | The URL of the provider repository | Both | +| `APPWRITE_VCS_REPOSITORY_BRANCH` | The branch used for the VCS deployment | Both | +| `APPWRITE_VCS_REPOSITORY_BRANCH_URL` | The URL of the branch used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_HASH` | The commit hash used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_MESSAGE` | The commit message used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_URL` | The URL of the commit used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_AUTHOR_NAME` | The name of the VCS commit author | Both | +| `APPWRITE_VCS_COMMIT_AUTHOR_URL` | The URL of the VCS commit author | Both | +| `APPWRITE_VCS_ROOT_DIRECTORY` | The root directory configured for the VCS deployment | Both | + +VCS metadata variables are populated for Git deployments. For manual and CLI deployments, VCS fields may be empty. From c6df96bede5b576e2c799af43dc6e7bf261a5ee4 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 12 Jun 2026 14:34:56 +0530 Subject: [PATCH 15/61] Format env var tables --- src/partials/functions-env-vars.md | 54 +++++++++++++++--------------- src/partials/sites-env-vars.md | 4 +-- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/partials/functions-env-vars.md b/src/partials/functions-env-vars.md index 1be0e446f26..bfd57444145 100644 --- a/src/partials/functions-env-vars.md +++ b/src/partials/functions-env-vars.md @@ -1,29 +1,29 @@ -| Variable | Description | Available at Build and/or Run Time | -| -------------------------------------- | ------------------------------------------------------------- | ---------------------------------- | -| `APPWRITE_FUNCTION_API_ENDPOINT` | The API endpoint of the running function | Both | -| `APPWRITE_VERSION` | The Appwrite version used to run the function | Both | -| `APPWRITE_REGION` | The region where the function will run from | Both | -| `APPWRITE_DEPLOYMENT_TYPE` | The deployment source type, such as `manual`, `cli`, or `vcs` | Both | -| `APPWRITE_FUNCTION_API_KEY` | The function API key used for server authentication | Build time | -| `APPWRITE_FUNCTION_ID` | The ID of the running function | Both | -| `APPWRITE_FUNCTION_NAME` | The name of the running function | Both | -| `APPWRITE_FUNCTION_DEPLOYMENT` | The deployment ID of the running function | Both | -| `APPWRITE_FUNCTION_PROJECT_ID` | The project ID of the running function | Both | -| `APPWRITE_FUNCTION_RUNTIME_NAME` | The runtime of the running function | Both | -| `APPWRITE_FUNCTION_RUNTIME_VERSION` | The runtime version of the running function | Both | -| `APPWRITE_FUNCTION_CPUS` | The CPU (runtime) specification of the running function | Both | -| `APPWRITE_FUNCTION_MEMORY` | The memory (runtime) specification of the running function | Both | -| `APPWRITE_VCS_REPOSITORY_ID` | The provider repository ID for VCS deployments | Both | -| `APPWRITE_VCS_REPOSITORY_NAME` | The provider repository name for VCS deployments | Both | -| `APPWRITE_VCS_REPOSITORY_OWNER` | The owner of the provider repository | Both | -| `APPWRITE_VCS_REPOSITORY_URL` | The URL of the provider repository | Both | -| `APPWRITE_VCS_REPOSITORY_BRANCH` | The branch used for the VCS deployment | Both | -| `APPWRITE_VCS_REPOSITORY_BRANCH_URL` | The URL of the branch used for the VCS deployment | Both | -| `APPWRITE_VCS_COMMIT_HASH` | The commit hash used for the VCS deployment | Both | -| `APPWRITE_VCS_COMMIT_MESSAGE` | The commit message used for the VCS deployment | Both | -| `APPWRITE_VCS_COMMIT_URL` | The URL of the commit used for the VCS deployment | Both | -| `APPWRITE_VCS_COMMIT_AUTHOR_NAME` | The name of the VCS commit author | Both | -| `APPWRITE_VCS_COMMIT_AUTHOR_URL` | The URL of the VCS commit author | Both | -| `APPWRITE_VCS_ROOT_DIRECTORY` | The root directory configured for the VCS deployment | Both | +| Variable | Description | Available at Build and/or Run Time | +| ------------------------------------ | ------------------------------------------------------------- | ---------------------------------- | +| `APPWRITE_FUNCTION_API_ENDPOINT` | The API endpoint of the running function | Both | +| `APPWRITE_VERSION` | The Appwrite version used to run the function | Both | +| `APPWRITE_REGION` | The region where the function will run from | Both | +| `APPWRITE_DEPLOYMENT_TYPE` | The deployment source type, such as `manual`, `cli`, or `vcs` | Both | +| `APPWRITE_FUNCTION_API_KEY` | The function API key used for server authentication | Build time | +| `APPWRITE_FUNCTION_ID` | The ID of the running function | Both | +| `APPWRITE_FUNCTION_NAME` | The name of the running function | Both | +| `APPWRITE_FUNCTION_DEPLOYMENT` | The deployment ID of the running function | Both | +| `APPWRITE_FUNCTION_PROJECT_ID` | The project ID of the running function | Both | +| `APPWRITE_FUNCTION_RUNTIME_NAME` | The runtime of the running function | Both | +| `APPWRITE_FUNCTION_RUNTIME_VERSION` | The runtime version of the running function | Both | +| `APPWRITE_FUNCTION_CPUS` | The CPU (runtime) specification of the running function | Both | +| `APPWRITE_FUNCTION_MEMORY` | The memory (runtime) specification of the running function | Both | +| `APPWRITE_VCS_REPOSITORY_ID` | The provider repository ID for VCS deployments | Both | +| `APPWRITE_VCS_REPOSITORY_NAME` | The provider repository name for VCS deployments | Both | +| `APPWRITE_VCS_REPOSITORY_OWNER` | The owner of the provider repository | Both | +| `APPWRITE_VCS_REPOSITORY_URL` | The URL of the provider repository | Both | +| `APPWRITE_VCS_REPOSITORY_BRANCH` | The branch used for the VCS deployment | Both | +| `APPWRITE_VCS_REPOSITORY_BRANCH_URL` | The URL of the branch used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_HASH` | The commit hash used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_MESSAGE` | The commit message used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_URL` | The URL of the commit used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_AUTHOR_NAME` | The name of the VCS commit author | Both | +| `APPWRITE_VCS_COMMIT_AUTHOR_URL` | The URL of the VCS commit author | Both | +| `APPWRITE_VCS_ROOT_DIRECTORY` | The root directory configured for the VCS deployment | Both | VCS metadata variables are populated for Git deployments. For manual and CLI deployments, VCS fields may be empty. diff --git a/src/partials/sites-env-vars.md b/src/partials/sites-env-vars.md index eef8cbcefae..936da5d21ef 100644 --- a/src/partials/sites-env-vars.md +++ b/src/partials/sites-env-vars.md @@ -11,8 +11,8 @@ | `APPWRITE_SITE_PROJECT_ID` | The project ID of the running site | Both | | `APPWRITE_SITE_RUNTIME_NAME` | The runtime name of the running site | Both | | `APPWRITE_SITE_RUNTIME_VERSION` | The runtime version of the running site | Both | -| `APPWRITE_SITE_CPUS` | The CPU (runtime) specification of the running site | Both | -| `APPWRITE_SITE_MEMORY` | The memory (runtime) specification of the running site | Both | +| `APPWRITE_SITE_CPUS` | The CPU (runtime) specification of the running site | Both | +| `APPWRITE_SITE_MEMORY` | The memory (runtime) specification of the running site | Both | | `APPWRITE_VCS_REPOSITORY_ID` | The provider repository ID for VCS deployments | Both | | `APPWRITE_VCS_REPOSITORY_NAME` | The provider repository name for VCS deployments | Both | | `APPWRITE_VCS_REPOSITORY_OWNER` | The owner of the provider repository | Both | From 5d62a68e6b0e4162f4edd43a29ed06e90a3baf85 Mon Sep 17 00:00:00 2001 From: adityaoberai Date: Tue, 23 Jun 2026 04:07:11 +0530 Subject: [PATCH 16/61] Flatten APIs nav and merge error handling into Response codes - Surface Events, Webhooks, and Response codes as top-level items in the APIs nav, replacing the "Events & Errors" grouping - Move those pages out of the (events-and-errors) route group to flat /docs/apis routes, each with its own layout - Merge the standalone Error handling page into the Response codes page; repoint the platform redirect and API reference link to the #error-handling anchor - Remove the Error handling card from the APIs overview page and fix the Realtime sub-nav back-link (/docs -> /docs/apis) Co-Authored-By: Claude Opus 4.8 (1M context) --- src/redirects.json | 2 +- src/routes/docs/Sidebar.svelte | 15 ++++- .../apis/(events-and-errors)/+layout.svelte | 43 ------------ .../error-handling/+page.markdoc | 67 ------------------- src/routes/docs/apis/(overview)/+page.markdoc | 11 ++- src/routes/docs/apis/events/+layout.svelte | 9 +++ .../events/+page.markdoc | 0 src/routes/docs/apis/realtime/+layout.svelte | 2 +- .../docs/apis/response-codes/+layout.svelte | 9 +++ .../response-codes/+page.markdoc | 29 +++++++- src/routes/docs/apis/webhooks/+layout.svelte | 9 +++ .../webhooks/+page.markdoc | 0 src/routes/docs/references/+page.markdoc | 2 +- 13 files changed, 73 insertions(+), 125 deletions(-) delete mode 100644 src/routes/docs/apis/(events-and-errors)/+layout.svelte delete mode 100644 src/routes/docs/apis/(events-and-errors)/error-handling/+page.markdoc create mode 100644 src/routes/docs/apis/events/+layout.svelte rename src/routes/docs/apis/{(events-and-errors) => }/events/+page.markdoc (100%) create mode 100644 src/routes/docs/apis/response-codes/+layout.svelte rename src/routes/docs/apis/{(events-and-errors) => }/response-codes/+page.markdoc (91%) create mode 100644 src/routes/docs/apis/webhooks/+layout.svelte rename src/routes/docs/apis/{(events-and-errors) => }/webhooks/+page.markdoc (100%) diff --git a/src/redirects.json b/src/redirects.json index bf25294a4f5..158fc514488 100644 --- a/src/redirects.json +++ b/src/redirects.json @@ -994,7 +994,7 @@ }, { "link": "/docs/advanced/platform/error-handling", - "redirect": "/docs/apis/error-handling" + "redirect": "/docs/apis/response-codes#error-handling" }, { "link": "/docs/advanced/platform/release-policy", diff --git a/src/routes/docs/Sidebar.svelte b/src/routes/docs/Sidebar.svelte index 11879d1300e..3f85c8d4123 100644 --- a/src/routes/docs/Sidebar.svelte +++ b/src/routes/docs/Sidebar.svelte @@ -132,10 +132,19 @@ isParent: true }, { - label: 'Events & Errors', + label: 'Events', href: '/docs/apis/events', - icon: 'icon-switch-horizontal', - isParent: true + icon: 'icon-switch-horizontal' + }, + { + label: 'Webhooks', + href: '/docs/apis/webhooks', + icon: 'icon-bell' + }, + { + label: 'Response codes', + href: '/docs/apis/response-codes', + icon: 'icon-code' } ] }, diff --git a/src/routes/docs/apis/(events-and-errors)/+layout.svelte b/src/routes/docs/apis/(events-and-errors)/+layout.svelte deleted file mode 100644 index e4a6ed85ba1..00000000000 --- a/src/routes/docs/apis/(events-and-errors)/+layout.svelte +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - diff --git a/src/routes/docs/apis/(events-and-errors)/error-handling/+page.markdoc b/src/routes/docs/apis/(events-and-errors)/error-handling/+page.markdoc deleted file mode 100644 index b1f7fb2cff9..00000000000 --- a/src/routes/docs/apis/(events-and-errors)/error-handling/+page.markdoc +++ /dev/null @@ -1,67 +0,0 @@ ---- -layout: article -title: Error handling -description: Best practices for handling Appwrite errors in your applications. Learn how to provide friendly error messages to your users while effectively troubleshooting issues. ---- - -When integrating Appwrite into your applications, proper error handling is important for delivering a good user experience while still being able to troubleshoot issues effectively. - -# Consider user-friendly error messages - -**It's generally best to avoid returning Appwrite's raw error messages directly to your users.** These messages are designed for developers and may contain technical details that: - -- Could confuse non-technical users -- Might expose implementation details -- Often create an inconsistent user experience - -Instead, consider this approach: - -1. Catch errors from Appwrite -2. Identify the error type -3. Return a user-friendly message appropriate for your application - -# Use error types for better handling - -Appwrite returns not just HTTP status codes but also specific error types that provide more precise information about what went wrong. These error types are available in the `type` field of the error response: - -```json -{ - "message": "Invalid credentials. Please check the email and password.", - "type": "user_invalid_credentials", - "code": 401 -} -``` - -By checking the error type rather than just the status code, you can create more precise error handling logic. This approach allows you to: - -- Display contextual error messages based on what actually went wrong -- Implement different recovery strategies for different error types -- Log specific errors for debugging while showing friendly messages to users -- Handle temporary issues (like network problems) differently from permanent ones - -# Common error types and suggested messages - -Here are some examples of how you might map Appwrite error types to user-friendly messages: - -| Error Type | Technical Meaning | User-Friendly Message | -|------------|-------------------|----------------------| -| `user_invalid_credentials` | Invalid credentials. Please check the email and password. | "The email or password you entered is incorrect. Please try again." | -| `user_blocked` | The current user has been blocked. | "Your account has been temporarily suspended. Please contact support." | -| `general_rate_limit_exceeded` | Rate limit for the current endpoint has been exceeded. | "Please wait a moment before trying again." | -| `storage_file_not_found` | The requested file could not be found. | "The file you requested is not available." | -| `row_not_found` | Row with the requested ID could not be found. | "The information you're looking for could not be found." | - -# Complete list of error types - -Appwrite provides a comprehensive list of error types organized by category. For a complete reference, see the [Response codes](/docs/apis/response-codes#error-types) documentation. - -# Recommended practices - -- **Log the actual errors server-side** for debugging while returning friendly messages to users -- **Handle common error scenarios** with specific user guidance -- **Provide clear next steps** when possible (e.g., "Try resetting your password") -- **Use consistent error message styling** throughout your application -- **Consider different error categories** (validation errors, authentication issues, server problems) -- **Consider implementing retry logic** for transient errors like rate limiting (429) or service unavailability (503) - -By implementing thoughtful error handling, you improve both the user experience of your application and your ability to troubleshoot issues effectively. \ No newline at end of file diff --git a/src/routes/docs/apis/(overview)/+page.markdoc b/src/routes/docs/apis/(overview)/+page.markdoc index 85ebdb3b1e7..ac618796e2d 100644 --- a/src/routes/docs/apis/(overview)/+page.markdoc +++ b/src/routes/docs/apis/(overview)/+page.markdoc @@ -24,7 +24,7 @@ Subscribe to channels and receive updates over WebSockets the moment your data c {% /cards_item %} {% /cards %} -# Event-driven workflows {% #events-and-errors %} +# Event-driven workflows {% #event-driven-workflows %} React to project changes with events emitted by Appwrite and webhooks delivered to your own endpoints. @@ -37,15 +37,12 @@ Trigger external workflows by delivering events to your own HTTP endpoints. {% /cards_item %} {% /cards %} -# API responses and errors {% #api-responses-and-errors %} +# API responses {% #api-responses %} -Understand the responses Appwrite returns and build error handling that helps your application recover gracefully. +Understand the responses Appwrite returns and handle errors so your application can recover gracefully. {% cards %} {% cards_item href="/docs/apis/response-codes" title="Response codes" %} -The HTTP status codes and error types returned by the Appwrite APIs. -{% /cards_item %} -{% cards_item href="/docs/apis/error-handling" title="Error handling" %} -Patterns for catching and handling errors gracefully in your application. +HTTP status codes, error types, and patterns for handling errors gracefully in your application. {% /cards_item %} {% /cards %} diff --git a/src/routes/docs/apis/events/+layout.svelte b/src/routes/docs/apis/events/+layout.svelte new file mode 100644 index 00000000000..93e22c8cebf --- /dev/null +++ b/src/routes/docs/apis/events/+layout.svelte @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/routes/docs/apis/(events-and-errors)/events/+page.markdoc b/src/routes/docs/apis/events/+page.markdoc similarity index 100% rename from src/routes/docs/apis/(events-and-errors)/events/+page.markdoc rename to src/routes/docs/apis/events/+page.markdoc diff --git a/src/routes/docs/apis/realtime/+layout.svelte b/src/routes/docs/apis/realtime/+layout.svelte index 31a59557e7e..28c8c64edfb 100644 --- a/src/routes/docs/apis/realtime/+layout.svelte +++ b/src/routes/docs/apis/realtime/+layout.svelte @@ -4,7 +4,7 @@ import { isNewUntil } from '$lib/utils/date'; const parent: NavParent = { - href: '/docs', + href: '/docs/apis', label: 'Realtime' }; diff --git a/src/routes/docs/apis/response-codes/+layout.svelte b/src/routes/docs/apis/response-codes/+layout.svelte new file mode 100644 index 00000000000..93e22c8cebf --- /dev/null +++ b/src/routes/docs/apis/response-codes/+layout.svelte @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/routes/docs/apis/(events-and-errors)/response-codes/+page.markdoc b/src/routes/docs/apis/response-codes/+page.markdoc similarity index 91% rename from src/routes/docs/apis/(events-and-errors)/response-codes/+page.markdoc rename to src/routes/docs/apis/response-codes/+page.markdoc index a0e462810af..0626c12f269 100644 --- a/src/routes/docs/apis/(events-and-errors)/response-codes/+page.markdoc +++ b/src/routes/docs/apis/response-codes/+page.markdoc @@ -1,7 +1,7 @@ --- layout: article title: Response codes -description: Understand Appwrite platform response codes for effective error handling. Learn how to interpret and handle response codes to enhance your application's reliability. +description: Understand Appwrite platform response codes and error handling. Learn to interpret HTTP status codes, error types, and implement best practices for handling errors gracefully. --- Appwrite uses conventional HTTP response codes to indicate the success or failure of an API request. @@ -226,4 +226,29 @@ Errors from the Appwrite GraphQL API. | Code | Type | Description | | ---- | ---- | ----------- | | 400 | graphql_no_query | Param "query" is not optional. | -| 400 | graphql_too_many_queries | Too many queries. | \ No newline at end of file +| 400 | graphql_too_many_queries | Too many queries. | + +# Error handling {% #error-handling %} + +The response codes and [error types](#error-types) above are the building blocks for handling errors. The practices below help you turn them into a recoverable, user-friendly experience. + +## Return user-friendly messages {% #user-friendly-messages %} + +Avoid surfacing Appwrite's raw error messages directly to your users. They're written for developers and can expose implementation details or confuse non-technical users. Instead, catch the error, inspect its `type`, and map it to a message that fits your application. + +The `type` field is more specific than the HTTP status code, so it lets you respond precisely: a `400` can mean many things, but `user_invalid_credentials` means exactly one. Matching on `type` also lets you treat a transient error like `general_rate_limit_exceeded` differently from a permanent one. + +| Error type | User-friendly message | +|------------|----------------------| +| `user_invalid_credentials` | "The email or password you entered is incorrect. Please try again." | +| `user_blocked` | "Your account has been temporarily suspended. Please contact support." | +| `general_rate_limit_exceeded` | "Please wait a moment before trying again." | +| `storage_file_not_found` | "The file you requested is not available." | +| `row_not_found` | "The information you're looking for could not be found." | + +## Recommended practices {% #recommended-practices %} + +- **Log the full error server-side** for debugging, while showing only the friendly message to users. +- **Handle common scenarios explicitly** and offer clear next steps, such as "Try resetting your password." +- **Retry transient errors** like rate limiting (`429`) or service unavailability (`503`), ideally with backoff. +- **Keep error messaging consistent** in tone and styling across your application. \ No newline at end of file diff --git a/src/routes/docs/apis/webhooks/+layout.svelte b/src/routes/docs/apis/webhooks/+layout.svelte new file mode 100644 index 00000000000..93e22c8cebf --- /dev/null +++ b/src/routes/docs/apis/webhooks/+layout.svelte @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/routes/docs/apis/(events-and-errors)/webhooks/+page.markdoc b/src/routes/docs/apis/webhooks/+page.markdoc similarity index 100% rename from src/routes/docs/apis/(events-and-errors)/webhooks/+page.markdoc rename to src/routes/docs/apis/webhooks/+page.markdoc diff --git a/src/routes/docs/references/+page.markdoc b/src/routes/docs/references/+page.markdoc index e3095b963fd..c5a6c7c8924 100644 --- a/src/routes/docs/references/+page.markdoc +++ b/src/routes/docs/references/+page.markdoc @@ -70,4 +70,4 @@ Track which signed-in users are active right now and broadcast their status in r ## Error handling {% #error-handling %} -When building with Appwrite, implement proper error handling to provide user-friendly messages instead of exposing raw error responses. For implementation details and best practices, refer to our [Error handling guide](/docs/apis/error-handling) and [Response codes](/docs/apis/response-codes#error-types) documentation. +When building with Appwrite, implement proper error handling to provide user-friendly messages instead of exposing raw error responses. For implementation details and best practices, refer to our [Error handling guide](/docs/apis/response-codes#error-handling) and [Response codes](/docs/apis/response-codes) documentation. From dbf2fa062339221535bfbbb7cdaaf0580ab540d3 Mon Sep 17 00:00:00 2001 From: adityaoberai Date: Wed, 24 Jun 2026 03:11:54 +0530 Subject: [PATCH 17/61] Fix APIs docs nav --- src/routes/docs/Sidebar.svelte | 15 ----- .../docs/apis/(overview)/+layout.svelte | 2 +- src/routes/docs/apis/Sidebar.svelte | 57 +++++++++++++++++++ src/routes/docs/apis/events/+layout.svelte | 2 +- src/routes/docs/apis/graphql/+layout.svelte | 2 +- .../docs/apis/response-codes/+layout.svelte | 2 +- src/routes/docs/apis/rest/+layout.svelte | 2 +- src/routes/docs/apis/webhooks/+layout.svelte | 2 +- 8 files changed, 63 insertions(+), 21 deletions(-) create mode 100644 src/routes/docs/apis/Sidebar.svelte diff --git a/src/routes/docs/Sidebar.svelte b/src/routes/docs/Sidebar.svelte index 3f85c8d4123..570328d2e66 100644 --- a/src/routes/docs/Sidebar.svelte +++ b/src/routes/docs/Sidebar.svelte @@ -130,21 +130,6 @@ href: '/docs/apis/realtime', icon: 'icon-clock', isParent: true - }, - { - label: 'Events', - href: '/docs/apis/events', - icon: 'icon-switch-horizontal' - }, - { - label: 'Webhooks', - href: '/docs/apis/webhooks', - icon: 'icon-bell' - }, - { - label: 'Response codes', - href: '/docs/apis/response-codes', - icon: 'icon-code' } ] }, diff --git a/src/routes/docs/apis/(overview)/+layout.svelte b/src/routes/docs/apis/(overview)/+layout.svelte index 93e22c8cebf..2416c16742b 100644 --- a/src/routes/docs/apis/(overview)/+layout.svelte +++ b/src/routes/docs/apis/(overview)/+layout.svelte @@ -1,6 +1,6 @@ diff --git a/src/routes/docs/apis/Sidebar.svelte b/src/routes/docs/apis/Sidebar.svelte new file mode 100644 index 00000000000..6cd2255a232 --- /dev/null +++ b/src/routes/docs/apis/Sidebar.svelte @@ -0,0 +1,57 @@ + + + diff --git a/src/routes/docs/apis/events/+layout.svelte b/src/routes/docs/apis/events/+layout.svelte index 93e22c8cebf..2416c16742b 100644 --- a/src/routes/docs/apis/events/+layout.svelte +++ b/src/routes/docs/apis/events/+layout.svelte @@ -1,6 +1,6 @@ diff --git a/src/routes/docs/apis/graphql/+layout.svelte b/src/routes/docs/apis/graphql/+layout.svelte index 93e22c8cebf..2416c16742b 100644 --- a/src/routes/docs/apis/graphql/+layout.svelte +++ b/src/routes/docs/apis/graphql/+layout.svelte @@ -1,6 +1,6 @@ diff --git a/src/routes/docs/apis/response-codes/+layout.svelte b/src/routes/docs/apis/response-codes/+layout.svelte index 93e22c8cebf..2416c16742b 100644 --- a/src/routes/docs/apis/response-codes/+layout.svelte +++ b/src/routes/docs/apis/response-codes/+layout.svelte @@ -1,6 +1,6 @@ diff --git a/src/routes/docs/apis/rest/+layout.svelte b/src/routes/docs/apis/rest/+layout.svelte index 93e22c8cebf..2416c16742b 100644 --- a/src/routes/docs/apis/rest/+layout.svelte +++ b/src/routes/docs/apis/rest/+layout.svelte @@ -1,6 +1,6 @@ diff --git a/src/routes/docs/apis/webhooks/+layout.svelte b/src/routes/docs/apis/webhooks/+layout.svelte index 93e22c8cebf..2416c16742b 100644 --- a/src/routes/docs/apis/webhooks/+layout.svelte +++ b/src/routes/docs/apis/webhooks/+layout.svelte @@ -1,6 +1,6 @@ From 8db4ea35af4dde0d9cd470abcc1488e64f8d2dbb Mon Sep 17 00:00:00 2001 From: adityaoberai Date: Wed, 24 Jun 2026 03:21:08 +0530 Subject: [PATCH 18/61] Shift release policy to API docs --- STYLE.md | 2 +- src/redirects.json | 6 +++++- src/routes/docs/Sidebar.svelte | 5 ----- src/routes/docs/apis/Sidebar.svelte | 9 +++++++++ .../{advanced => apis}/release-policy/+layout.svelte | 2 +- .../docs/{advanced => apis}/release-policy/+page.markdoc | 0 6 files changed, 16 insertions(+), 8 deletions(-) rename src/routes/docs/{advanced => apis}/release-policy/+layout.svelte (75%) rename src/routes/docs/{advanced => apis}/release-policy/+page.markdoc (100%) diff --git a/STYLE.md b/STYLE.md index 646bf44645b..5571caa22ea 100644 --- a/STYLE.md +++ b/STYLE.md @@ -51,6 +51,7 @@ APIs section: - [Events](https://appwrite.io/docs/apis/events) - [Webhooks](https://appwrite.io/docs/apis/webhooks) - [Response codes](https://appwrite.io/docs/apis/response-codes) +- [Release policy](https://appwrite.io/docs/apis/release-policy) - [Error handling](https://appwrite.io/docs/apis/error-handling) Tooling section: @@ -65,7 +66,6 @@ Advanced section: - [Migrations](https://appwrite.io/docs/advanced/migrations) - [Self-hosting](https://appwrite.io/docs/advanced/self-hosting) - [Security](https://appwrite.io/docs/advanced/security) -- [Release policy](https://appwrite.io/docs/advanced/release-policy) Here's the intended purpose and structure of each section. diff --git a/src/redirects.json b/src/redirects.json index 158fc514488..af48ad0536c 100644 --- a/src/redirects.json +++ b/src/redirects.json @@ -998,7 +998,11 @@ }, { "link": "/docs/advanced/platform/release-policy", - "redirect": "/docs/advanced/release-policy" + "redirect": "/docs/apis/release-policy" + }, + { + "link": "/docs/advanced/release-policy", + "redirect": "/docs/apis/release-policy" }, { "link": "/docs/advanced/platform/permissions", diff --git a/src/routes/docs/Sidebar.svelte b/src/routes/docs/Sidebar.svelte index 570328d2e66..a3334b9bdc1 100644 --- a/src/routes/docs/Sidebar.svelte +++ b/src/routes/docs/Sidebar.svelte @@ -199,11 +199,6 @@ href: '/docs/advanced/self-hosting', icon: 'icon-server', isParent: true - }, - { - label: 'Release policy', - href: '/docs/advanced/release-policy', - icon: 'icon-tag' } ] } diff --git a/src/routes/docs/apis/Sidebar.svelte b/src/routes/docs/apis/Sidebar.svelte index 6cd2255a232..ff13fb2fa77 100644 --- a/src/routes/docs/apis/Sidebar.svelte +++ b/src/routes/docs/apis/Sidebar.svelte @@ -50,6 +50,15 @@ href: '/docs/apis/response-codes' } ] + }, + { + label: 'Policies', + items: [ + { + label: 'Release policy', + href: '/docs/apis/release-policy' + } + ] } ]; diff --git a/src/routes/docs/advanced/release-policy/+layout.svelte b/src/routes/docs/apis/release-policy/+layout.svelte similarity index 75% rename from src/routes/docs/advanced/release-policy/+layout.svelte rename to src/routes/docs/apis/release-policy/+layout.svelte index 93e22c8cebf..2416c16742b 100644 --- a/src/routes/docs/advanced/release-policy/+layout.svelte +++ b/src/routes/docs/apis/release-policy/+layout.svelte @@ -1,6 +1,6 @@ diff --git a/src/routes/docs/advanced/release-policy/+page.markdoc b/src/routes/docs/apis/release-policy/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/release-policy/+page.markdoc rename to src/routes/docs/apis/release-policy/+page.markdoc From c282744fb80ddedaacd305c4987d4bc77afdd0aa Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Wed, 24 Jun 2026 18:02:14 +0530 Subject: [PATCH 19/61] Add React library launch cover, changelog entry, beta tag Sets the announcement blog cover to the new React SDK artwork (date moved to 2026-06-24), adds the matching 2026-06-24 changelog entry, and tags the React library row in /docs/sdks as beta to align with the React Native SDK row. --- .optimize-cache.json | 1 + .../+page.markdoc | 2 +- .../changelog/(entries)/2026-06-24.markdoc | 14 ++++++++++++++ src/routes/docs/sdks/+page.markdoc | 2 +- .../announcing-appwrite-react-library/cover.avif | Bin 0 -> 9139 bytes 5 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 src/routes/changelog/(entries)/2026-06-24.markdoc create mode 100644 static/images/blog/announcing-appwrite-react-library/cover.avif diff --git a/.optimize-cache.json b/.optimize-cache.json index f926af4a597..fdd5dc77113 100644 --- a/.optimize-cache.json +++ b/.optimize-cache.json @@ -202,6 +202,7 @@ "static/images/blog/announcing-appwrite-pro/credits.png": "285905e1fd8b8282cb45a4f2259debd851812c23665145d865e141f5133c0be0", "static/images/blog/announcing-appwrite-pro/header.png": "ab709ff45870607ec4472bd4dc9e4a028e320bbfb89009ec04c98ec69248a15a", "static/images/blog/announcing-appwrite-pro/pro.png": "01427f30610de4d6d19cd9160154d8849ffa75da04d063d12bf3e9bba481b4e7", + "static/images/blog/announcing-appwrite-react-library/cover.png": "db2536faba9c82ad441662e10bf69375c8f6d1716e151324e37b0a5bbca9ee48", "static/images/blog/announcing-appwrite-rust-sdk/cover.png": "b5b69e19f4fc1ac5eb985016c1b058bb9ed308680197f315f3b9b861f3377310", "static/images/blog/announcing-atomic-numeric-operations/cover.png": "9fbe339856b8040eb49fb01ca4353b5600609962ab8044dcfc34ffbe0e8a9738", "static/images/blog/announcing-auto-increment-support/cover.png": "83a7b1dd0e31ae86e49fa873cde0b6c0319a552b27dc447b4a214efd7f3fd534", diff --git a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc index 62756ee3bd1..d7641121c91 100644 --- a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc +++ b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc @@ -2,7 +2,7 @@ layout: post title: "Announcing the Appwrite React library" description: A small set of React hooks and SSR adapters that take the busywork out of wiring Appwrite Auth into Vite, Next.js, and TanStack Start apps. -date: 2026-05-25 +date: 2026-06-24 cover: /images/blog/announcing-appwrite-react-library/cover.avif timeToRead: 5 author: atharva diff --git a/src/routes/changelog/(entries)/2026-06-24.markdoc b/src/routes/changelog/(entries)/2026-06-24.markdoc new file mode 100644 index 00000000000..00dd5d62cf3 --- /dev/null +++ b/src/routes/changelog/(entries)/2026-06-24.markdoc @@ -0,0 +1,14 @@ +--- +layout: changelog +title: 'Announcing the Appwrite React library' +date: 2026-06-24 +cover: /images/blog/announcing-appwrite-react-library/cover.avif +--- + +The **Appwrite React library** is now available. It is primarily made for authentication for now, shipping an `AppwriteProvider` and a small set of hooks (`useAuth`, `useUser`, `useSignIn`, `useSignUp`, `useSignOut`) that handle the boilerplate around session hydration, OAuth, and current user state. + +The Appwrite React library helps with authentication across client-side rendered frameworks and server-side rendered frameworks such as **Next.js** and **TanStack Start**. + +{% arrow_link href="/blog/post/announcing-appwrite-react-library" %} +Read the announcement +{% /arrow_link %} diff --git a/src/routes/docs/sdks/+page.markdoc b/src/routes/docs/sdks/+page.markdoc index e9bad0db8f5..7ab2e2e11db 100644 --- a/src/routes/docs/sdks/+page.markdoc +++ b/src/routes/docs/sdks/+page.markdoc @@ -34,7 +34,7 @@ Client libraries for integrating with Appwrite to build client-based application {% only_light %}{% icon_image src="/images/platforms/light/react.svg" alt="React logo" size="m" /%}{% /only_light %} * React library `0.1.0` * [appwrite/sdk-for-react](https://github.com/appwrite/sdk-for-react) -* +* `beta` --- * {% only_dark %}{% icon_image src="/images/platforms/dark/react.svg" alt="React logo" size="m" /%}{% /only_dark %} {% only_light %}{% icon_image src="/images/platforms/light/react.svg" alt="React logo" size="m" /%}{% /only_light %} diff --git a/static/images/blog/announcing-appwrite-react-library/cover.avif b/static/images/blog/announcing-appwrite-react-library/cover.avif new file mode 100644 index 0000000000000000000000000000000000000000..dbbd9b87a40fd450ae0d3c7b2567ca86b03657e4 GIT binary patch literal 9139 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 literal 0 HcmV?d00001 From 0c2aa5088a323131efb25e2bc325cc4700d7180f Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Fri, 26 Jun 2026 07:25:43 +0200 Subject: [PATCH 20/61] ci: move production deploy to declarative setup, target default.yaml Replace production's imperative Helm deploy with the same declarative flow staging uses: bump the image tag in the assets-applications repo via a GitHub App token, then commit & push. Point both staging and production at default.yaml instead of fra1.yaml. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/production.yml | 69 ++++++++++++++------------------ .github/workflows/staging.yml | 4 +- 2 files changed, 31 insertions(+), 42 deletions(-) diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 2a3b7b22780..c1347bcec2f 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -6,10 +6,11 @@ on: workflow_dispatch: env: + ENVIRONMENT: production + PROJECT: website + DECLARATIVE_OWNER: appwrite-labs + DECLARATIVE_REPOSITORY: assets-applications TAG: ${{ github.event.release.tag_name || github.sha }} - STACK_FILE: docker/production.yml - REPOSITORY: website - REGISTRY_USERNAME: christyjacob4 jobs: build: @@ -49,49 +50,37 @@ jobs: "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" "SENTRY_RELEASE=${{ github.event.release.tag_name }}" - deploy_kubernetes: + deploy: if: github.event_name != 'release' || !contains(github.event.release.tag_name, '-rc') - strategy: - matrix: - region: [{ full: fra1, short: fra }] needs: build runs-on: ubuntu-latest steps: - - name: Checkout the repo - uses: actions/checkout@v4 - - name: Install Kubectl - uses: azure/setup-kubectl@v4 - - name: Install Helm - uses: azure/setup-helm@v4 - - name: Install doctl - uses: digitalocean/action-doctl@v2 + - name: Get token for ${{ env.DECLARATIVE_REPOSITORY }} + id: app-token + uses: actions/create-github-app-token@v2 with: - token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} - - name: Save DigitalOcean kubeconfig with short-lived credentials - run: doctl kubernetes cluster kubeconfig save --expiry-seconds 600 assets-${{ matrix.region.full }}-prod - - - name: Ensure namespaces exist - run: | - kubectl create namespace website --dry-run=client -o yaml | kubectl apply -f - + app-id: ${{ vars.DECLARATIVE_DEPLOYMENT_GITHUB_APP_ID }} + private-key: ${{ secrets.DECLARATIVE_DEPLOYMENT_GITHUB_APP_PRIVATE_KEY }} + owner: ${{ env.DECLARATIVE_OWNER }} + repositories: ${{ env.DECLARATIVE_REPOSITORY }} - - name: Create docker pull secret - run: | - kubectl -n website create secret docker-registry ghcr \ - --docker-server=ghcr.io \ - --docker-username=${{ secrets.GHCR_USERNAME }} \ - --docker-password=${{ secrets.GHCR_TOKEN }} \ - --docker-email=ci@appwrite.io \ - --dry-run=client -o yaml | kubectl apply -f - + - name: Checkout ${{ env.DECLARATIVE_REPOSITORY }} + uses: actions/checkout@v6 + with: + repository: ${{ env.DECLARATIVE_OWNER }}/${{ env.DECLARATIVE_REPOSITORY }} + token: ${{ steps.app-token.outputs.token }} - - name: Create app secrets - run: | - kubectl -n website create secret generic website-secrets \ - --from-literal=STATSIG_SERVER_SECRET='${{ secrets.STATSIG_SERVER_SECRET }}' \ - --dry-run=client -o yaml | kubectl apply -f - + - name: Update image tag + run: yq -i '.website.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml - - name: Deploy + - name: Commit and push run: | - helm upgrade --install --namespace website website deploy/website/ \ - --values deploy/website/environments/production/${{ matrix.region.full }}.values.yaml \ - --set imagePullSecret='ghcr' \ - --set version=${{ env.TAG }} + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml + if git diff --cached --quiet; then + echo "No changes to commit" + else + git commit -m "chore(${{ env.ENVIRONMENT }}): ${{ env.PROJECT }} image tag to ${{ env.TAG }}" + git push + fi diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index a581c48fbf5..9ed6307c28c 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -86,13 +86,13 @@ jobs: token: ${{ steps.app-token.outputs.token }} - name: Update image tag - run: yq -i '.website.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/fra1.yaml + run: yq -i '.website.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml - name: Commit and push run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/fra1.yaml + git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml if git diff --cached --quiet; then echo "No changes to commit" else From c4c2d1c83f0b0b50a5ed182f53f57df7096f5376 Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Fri, 26 Jun 2026 07:26:38 +0200 Subject: [PATCH 21/61] ci: use release tag instead of sha for production image tag Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/production.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index c1347bcec2f..55d07d85762 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -10,7 +10,7 @@ env: PROJECT: website DECLARATIVE_OWNER: appwrite-labs DECLARATIVE_REPOSITORY: assets-applications - TAG: ${{ github.event.release.tag_name || github.sha }} + TAG: ${{ github.event.release.tag_name }} jobs: build: From 702501fdea55414baf53ac6a7916ebd6d7971023 Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Fri, 26 Jun 2026 07:33:12 +0200 Subject: [PATCH 22/61] ci: make declarative deploy push resilient to concurrent runs Rebase-and-retry on push rejection so a staging and production deploy (or any other writer to assets-applications) racing on the same repo no longer fails with a non-fast-forward error. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/production.yml | 14 +++++++++++--- .github/workflows/staging.yml | 14 +++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 55d07d85762..8785bc1aed6 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -80,7 +80,15 @@ jobs: git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml if git diff --cached --quiet; then echo "No changes to commit" - else - git commit -m "chore(${{ env.ENVIRONMENT }}): ${{ env.PROJECT }} image tag to ${{ env.TAG }}" - git push + exit 0 fi + git commit -m "chore(${{ env.ENVIRONMENT }}): ${{ env.PROJECT }} image tag to ${{ env.TAG }}" + for attempt in 1 2 3 4 5; do + if git push; then + exit 0 + fi + echo "Push rejected (attempt $attempt), rebasing onto latest and retrying..." + git pull --rebase + done + echo "Failed to push after 5 attempts" >&2 + exit 1 diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index 9ed6307c28c..e5707f1ea71 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -95,7 +95,15 @@ jobs: git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml if git diff --cached --quiet; then echo "No changes to commit" - else - git commit -m "chore(${{ env.ENVIRONMENT }}): ${{ env.PROJECT }} image tag to ${{ env.TAG }}" - git push + exit 0 fi + git commit -m "chore(${{ env.ENVIRONMENT }}): ${{ env.PROJECT }} image tag to ${{ env.TAG }}" + for attempt in 1 2 3 4 5; do + if git push; then + exit 0 + fi + echo "Push rejected (attempt $attempt), rebasing onto latest and retrying..." + git pull --rebase + done + echo "Failed to push after 5 attempts" >&2 + exit 1 From e2a57d8e2ec824d5b51333a93880ed0258e241d1 Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Fri, 26 Jun 2026 07:35:42 +0200 Subject: [PATCH 23/61] ci: serialize declarative deploys with a shared concurrency group Job-level concurrency group shared across staging and production so their deploy jobs never run simultaneously, while their build jobs still run in parallel. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/production.yml | 3 +++ .github/workflows/staging.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 8785bc1aed6..1517a816ed0 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -54,6 +54,9 @@ jobs: if: github.event_name != 'release' || !contains(github.event.release.tag_name, '-rc') needs: build runs-on: ubuntu-latest + concurrency: + group: declarative-deploy-website + cancel-in-progress: false steps: - name: Get token for ${{ env.DECLARATIVE_REPOSITORY }} id: app-token diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index e5707f1ea71..305e630ae31 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -69,6 +69,9 @@ jobs: deploy: needs: build runs-on: ubuntu-latest + concurrency: + group: declarative-deploy-website + cancel-in-progress: false steps: - name: Get token for ${{ env.DECLARATIVE_REPOSITORY }} id: app-token From 17aa9968686d27b149e0eef79db14515f3be2a16 Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Fri, 26 Jun 2026 07:38:51 +0200 Subject: [PATCH 24/61] ci: drop push rebase-retry, rely on shared concurrency group The declarative-deploy-website concurrency group already serializes the staging and production deploys, so the rebase-retry loop is no longer needed. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/production.yml | 14 +++----------- .github/workflows/staging.yml | 14 +++----------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 1517a816ed0..f29249e18d5 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -83,15 +83,7 @@ jobs: git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml if git diff --cached --quiet; then echo "No changes to commit" - exit 0 + else + git commit -m "chore(${{ env.ENVIRONMENT }}): ${{ env.PROJECT }} image tag to ${{ env.TAG }}" + git push fi - git commit -m "chore(${{ env.ENVIRONMENT }}): ${{ env.PROJECT }} image tag to ${{ env.TAG }}" - for attempt in 1 2 3 4 5; do - if git push; then - exit 0 - fi - echo "Push rejected (attempt $attempt), rebasing onto latest and retrying..." - git pull --rebase - done - echo "Failed to push after 5 attempts" >&2 - exit 1 diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index 305e630ae31..98f12eca8f7 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -98,15 +98,7 @@ jobs: git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml if git diff --cached --quiet; then echo "No changes to commit" - exit 0 + else + git commit -m "chore(${{ env.ENVIRONMENT }}): ${{ env.PROJECT }} image tag to ${{ env.TAG }}" + git push fi - git commit -m "chore(${{ env.ENVIRONMENT }}): ${{ env.PROJECT }} image tag to ${{ env.TAG }}" - for attempt in 1 2 3 4 5; do - if git push; then - exit 0 - fi - echo "Push rejected (attempt $attempt), rebasing onto latest and retrying..." - git pull --rebase - done - echo "Failed to push after 5 attempts" >&2 - exit 1 From dbd50a392a3d8bbb146386759f409332be8e737f Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Fri, 26 Jun 2026 07:39:26 +0200 Subject: [PATCH 25/61] ci: fall back to sha when no release tag is present Restores the github.sha fallback so manual workflow_dispatch runs, which have no release tag, still produce a valid image tag. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/production.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index f29249e18d5..3d1334cd0c5 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -10,7 +10,7 @@ env: PROJECT: website DECLARATIVE_OWNER: appwrite-labs DECLARATIVE_REPOSITORY: assets-applications - TAG: ${{ github.event.release.tag_name }} + TAG: ${{ github.event.release.tag_name || github.sha }} jobs: build: From 78656fc1c2dc36ee9a82257538bb709241e363cb Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Fri, 26 Jun 2026 07:51:23 +0200 Subject: [PATCH 26/61] ci: pin workflow action steps to commit SHAs Pin all third-party actions in the staging and production workflows to immutable commit SHAs (with version comments) instead of mutable tags. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/production.yml | 10 +++++----- .github/workflows/staging.yml | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 3d1334cd0c5..07a6a2af535 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -17,17 +17,17 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v6 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . push: true @@ -60,7 +60,7 @@ jobs: steps: - name: Get token for ${{ env.DECLARATIVE_REPOSITORY }} id: app-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 with: app-id: ${{ vars.DECLARATIVE_DEPLOYMENT_GITHUB_APP_ID }} private-key: ${{ secrets.DECLARATIVE_DEPLOYMENT_GITHUB_APP_PRIVATE_KEY }} @@ -68,7 +68,7 @@ jobs: repositories: ${{ env.DECLARATIVE_REPOSITORY }} - name: Checkout ${{ env.DECLARATIVE_REPOSITORY }} - uses: actions/checkout@v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: repository: ${{ env.DECLARATIVE_OWNER }}/${{ env.DECLARATIVE_REPOSITORY }} token: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index 98f12eca8f7..3736ba9d148 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -25,24 +25,24 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Login to GitHub Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ${{ env.REGISTRY_GITHUB }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ${{ env.REGISTRY_DOCKERHUB }} username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v6 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . push: true @@ -75,7 +75,7 @@ jobs: steps: - name: Get token for ${{ env.DECLARATIVE_REPOSITORY }} id: app-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 with: app-id: ${{ vars.DECLARATIVE_DEPLOYMENT_GITHUB_APP_ID }} private-key: ${{ secrets.DECLARATIVE_DEPLOYMENT_GITHUB_APP_PRIVATE_KEY }} @@ -83,7 +83,7 @@ jobs: repositories: ${{ env.DECLARATIVE_REPOSITORY }} - name: Checkout ${{ env.DECLARATIVE_REPOSITORY }} - uses: actions/checkout@v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: repository: ${{ env.DECLARATIVE_OWNER }}/${{ env.DECLARATIVE_REPOSITORY }} token: ${{ steps.app-token.outputs.token }} From e0009455ca33fdd024b06a6aae4c1ba94e994f10 Mon Sep 17 00:00:00 2001 From: Aishwari Pahwa Date: Fri, 26 Jun 2026 14:44:12 +0530 Subject: [PATCH 27/61] latest seo blog --- .optimize-cache.json | 1 + .../+page.markdoc | 143 ++++++++++++++++++ .../cover.avif | Bin 0 -> 14123 bytes 3 files changed, 144 insertions(+) create mode 100644 src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc create mode 100644 static/images/blog/what-is-cicd-a-complete-guide-for-developers/cover.avif diff --git a/.optimize-cache.json b/.optimize-cache.json index f926af4a597..942f5774fc0 100644 --- a/.optimize-cache.json +++ b/.optimize-cache.json @@ -1257,6 +1257,7 @@ "static/images/blog/what-is-an-ai-backend/cover.png": "cb36f49035cbdcd97a70ac658783741f275d3a220b7cfd16b39d4fb86a929edd", "static/images/blog/what-is-cdn/cover.png": "ef77860288e150c6c22f3950a5eae4c88aefefb6db204f10c2a0544e51548703", "static/images/blog/what-is-ciam/cover.png": "45a5261ae1bb8a38777f60a21ea60426c0832e3d58bf3164100548400d388ce1", + "static/images/blog/what-is-cicd-a-complete-guide-for-developers/cover.png": "7abddce55b1467188faab83abd58189173bf9aba84de3d9f28fff0be8c6e9276", "static/images/blog/what-is-docker-a-simple-guide-for-developers/cover.png": "acd9c50ad749fcf676dd58b38cc6bbffba913bf5d817c6b725bd2c305088689e", "static/images/blog/what-is-mcp/claude-mcp-chat.png": "26842cfebca3ec2cec89448e1c0d7ddb3f5421cc57acdb8780d48d30a54cad82", "static/images/blog/what-is-mcp/claude-mcp-tools.png": "3a5ae700867b8671b5c9e3af61b094aeb64611168463db66ff440e0d427ac6bc", diff --git a/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc b/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc new file mode 100644 index 00000000000..e7ae41c2528 --- /dev/null +++ b/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc @@ -0,0 +1,143 @@ +--- +layout: post +title: What is CI/CD? A complete guide for developers +description: Learn what CI/CD means, how continuous integration and delivery work, the pipeline stages, delivery vs deployment, and best practices, in this developer guide. +date: 2026-06-26 +cover: /images/blog/what-is-cicd-a-complete-guide-for-developers/cover.avif +timeToRead: 5 +author: atharva +category: devops +featured: false +unlisted: true +faqs: + - question: "What's the difference between CI and CD?" + answer: "CI (continuous integration) automates building and testing code as it's merged. CD (continuous delivery or deployment) automates releasing that tested code to production." + - question: Do I need Docker or Kubernetes for CI/CD? + answer: No, but they pair well. CI/CD works with any deployment target. Containers and orchestration simply make builds more consistent and deployments more reliable. + - question: Is CI/CD only for large teams? + answer: No. Even solo developers benefit from automated testing and deployment. You can start with a simple pipeline and expand it as your project grows. + - question: Is CI/CD the same as DevOps? + answer: No. DevOps is a broader culture and set of practices for uniting development and operations. CI/CD is a key technical practice within DevOps, but DevOps also covers monitoring, infrastructure, and collaboration. +--- +CI/CD is a set of practices that automate building, testing, and releasing software, so teams can ship changes quickly, frequently, and reliably. It stands for continuous integration and continuous delivery (or continuous deployment), and together these practices form the backbone of modern software development and DevOps. + +This guide explains what CI/CD is, what each part means, how a pipeline works, the difference between delivery and deployment, the tools that power it, and how to get started. It's written for developers who want a complete picture, not just a definition. + +# What does CI/CD stand for? + +CI/CD combines two related practices. **CI** stands for **continuous integration**, the practice of frequently merging code changes into a shared repository, where each change is automatically built and tested. **CD** stands for either **continuous delivery** or **continuous deployment**, both of which automate getting that tested code into production. + +You can think of CI/CD as an assembly line for software. Instead of manually compiling, testing, and shipping every change by hand, you build an automated line that takes code from a developer's commit and moves it through a series of checks until it's ready to release, or released automatically. The goal is to make releasing software a routine, low-risk event rather than a stressful, error-prone one. + +CI/CD grew out of the DevOps movement, which aims to break down the wall between development and operations. By automating the path from code to production, teams release faster and with more confidence. + +# Why does CI/CD matter? + +CI/CD matters because manual building, testing, and deploying is slow, inconsistent, and error-prone. Here is why teams adopt it: + +* **Faster releases.** Automation lets teams ship updates daily or even many times a day instead of every few weeks or months. +* **Fewer bugs in production.** Automated testing on every change catches problems early, when they're cheapest to fix. +* **Consistency.** The same automated process runs every time, eliminating "it worked on my machine" surprises. +* **Faster feedback.** Developers learn within minutes whether a change broke something, instead of finding out days later. +* **Less risk.** Small, frequent releases are easier to test and roll back than large, infrequent ones. + +# What is continuous integration (CI)? + +Continuous integration is the practice of merging code changes into a shared branch frequently, often several times a day, with each merge triggering an automated build and test run. The core idea is that integrating small changes often is far less painful than integrating large changes rarely. + +When a developer pushes code, a CI system automatically pulls the latest code, builds it, and runs the test suite. If anything fails, the team is notified immediately and can fix it before it spreads. This keeps the shared codebase in a working state at all times and prevents the dreaded "integration hell" of merging months of divergent work at once. + +Good CI depends on a strong automated test suite, because the tests are what give the team confidence that each change is safe. + +# What is continuous delivery and continuous deployment (CD)? + +The "CD" in CI/CD refers to two related but distinct practices. + +**Continuous delivery** means every change that passes the automated pipeline is automatically prepared and ready to release to production, but the final release is triggered manually by a human. The software is always in a deployable state, and shipping is a one-click decision. + +**Continuous deployment** goes one step further: every change that passes all automated checks is released to production automatically, with no human approval step. This requires a high degree of confidence in your automated tests, since there's no manual gate before users see the change. + +Both build on continuous integration. The difference is simply whether the final push to production is automatic or requires a human to press the button. + +# How does a CI/CD pipeline work? + +A **CI/CD pipeline** is the automated sequence of steps that code passes through on its way from commit to production. While details vary, most pipelines share the same core stages: + +1. **Source.** A developer pushes code to a repository, which triggers the pipeline. +2. **Build.** The system compiles the code and its dependencies into a runnable artifact, often a [Docker](https://www.docker.com/) container image. +3. **Test.** Automated tests run, from fast unit tests to integration and end-to-end tests, validating the change. +4. **Deploy.** The artifact is released to an environment, such as staging or production, sometimes managed by [Kubernetes](https://kubernetes.io/). + +Each stage acts as a gate: if a step fails, the pipeline stops and the team is notified, so broken code never reaches users. Many pipelines also include extra stages for security scanning, performance checks, and approvals. + +# Continuous delivery vs continuous deployment: What's the difference? + +This is the most common point of confusion in CI/CD, so it's worth being precise. Both keep your software in a constantly releasable state. The only difference is the final step to production. + +| Aspect | Continuous delivery | Continuous deployment | +| --------------------- | ------------------------------ | ----------------------------------- | +| Release to production | Manual approval | Fully automatic | +| Human gate | Yes, a person clicks deploy | No gate | +| Confidence required | High | Very high | +| Best for | Regulated or cautious releases | Fast-moving teams with strong tests | + +Many teams start with continuous delivery to keep a human in the loop, then move to continuous deployment as their test coverage and confidence grow. + +# Popular CI/CD tools + +A range of tools automate CI/CD pipelines, and most integrate directly with your code repository: + +* **GitHub Actions**, built into GitHub, defines pipelines as YAML workflows right alongside your code. +* **GitLab CI/CD**, tightly integrated with GitLab repositories. +* **Jenkins**, a long-standing open-source automation server known for its flexibility and plugins. You can learn more at [jenkins.io](https://www.jenkins.io/). +* **CircleCI** and **Travis CI**, popular cloud-based CI/CD services. + +Many of these work hand in hand with containers and orchestration, building Docker images in the pipeline and deploying them to Kubernetes or a managed platform. + +# Common CI/CD use cases + +* **Web and mobile app delivery.** Automatically test and ship application updates on every merge. +* **Microservices.** Deploy many independent services reliably without coordinating manual releases. +* **Library and package publishing.** Automatically run tests and publish new versions when code is tagged. +* **Infrastructure as code.** Apply and validate infrastructure changes through the same automated pipeline. +* **Automated quality gates.** Enforce tests, linting, and security scans before any code merges. + +# How to get started with CI/CD + +Getting started is easier than it sounds, and you can begin small. + +1. **Put your code in version control** like Git, which is the foundation everything else builds on. +2. **Write automated tests**, even a small suite, since CI is only as valuable as the tests it runs. +3. **Choose a CI/CD tool**, such as GitHub Actions if your code is already on GitHub. +4. **Create a simple pipeline** that builds your project and runs your tests on every push. +5. **Add a deployment stage** to ship to a staging environment, then production, as your confidence grows. + +A backend platform like [Appwrite](https://appwrite.io/docs) pairs well with CI/CD, giving you auth, databases, storage, and functions that your pipeline can deploy against. + +# CI/CD best practices + +* **Keep the pipeline fast** so developers get feedback in minutes, not hours. +* **Build once, deploy everywhere.** Create a single artifact and promote it through environments rather than rebuilding. +* **Automate your tests thoroughly**, since the pipeline's value depends entirely on test quality. +* **Fail fast.** Run the quickest checks first so failures surface early. +* **Keep secrets out of your pipeline config**, using a secrets manager or encrypted variables. +* **Make rollbacks easy** so you can recover instantly if a release causes problems. + +# Conclusion + +CI/CD is the practice of automating the path from code to production, combining continuous integration to build and test every change with continuous delivery or deployment to release it reliably. Understanding its core pieces, namely the integration of frequent changes, the automated pipeline stages, and the distinction between delivery and deployment, gives you the foundation to ship software faster and with far more confidence. It's one of the highest-impact habits a team can adopt, and it scales from a solo project to a large organization. The best way to learn CI/CD is to build a simple pipeline that tests your code on every push, then grow it one stage at a time. + +# Start building + +Appwrite is open-source, self-hostable, and built for developers who want to ship fast without surrendering control. Recent releases have added [MongoDB support, Appwrite 1.9.0, realtime upgrades, and new AI tooling](https://dev.to/appwrite/april-product-update-mongodb-support-appwrite-190-realtime-upgrades-and-ai-tooling-1eg6), with [more landing every few weeks](https://dev.to/appwrite/may-product-update-presences-api-rust-runtime-7x-faster-storage-uploads-and-more-9h5). We post weekly roundups of product announcements, AI updates, and [developer insights](https://dev.to/appwrite/weekly-roundup-presences-api-git-deployment-triggers-and-ai-updates-58lj) on the [Appwrite blog](https://appwrite.io/blog) and across our developer channels, so follow along wherever you read. + +Whether you are prototyping your next idea or scaling a production app, Appwrite gives you auth, databases, storage, functions, and real-time in one place, all open-source. [Sign up for Appwrite Cloud](https://cloud.appwrite.io/) or spin up a self-hosted instance in minutes, and give your next build a real backend to grow on. + +## Resources + +* [Appwrite documentation](https://appwrite.io/docs) +* [Appwrite AI products](https://appwrite.io/docs/products/ai) +* [Appwrite integrations](https://appwrite.io/integrations) +* [Appwrite quick start guides](https://appwrite.io/docs/quick-starts) +* [Appwrite on GitHub](https://github.com/appwrite/appwrite) +* [Join the Appwrite Discord](https://appwrite.io/discord) \ No newline at end of file diff --git a/static/images/blog/what-is-cicd-a-complete-guide-for-developers/cover.avif b/static/images/blog/what-is-cicd-a-complete-guide-for-developers/cover.avif new file mode 100644 index 0000000000000000000000000000000000000000..52b6f963b841d6c9f16d72e4e71df37c2d60da21 GIT binary patch literal 14123 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 Date: Fri, 26 Jun 2026 15:09:36 +0530 Subject: [PATCH 28/61] Apply suggestion from @greptile-apps[bot] Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- .../what-is-cicd-a-complete-guide-for-developers/+page.markdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc b/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc index e7ae41c2528..0ed36f1bf8d 100644 --- a/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc +++ b/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc @@ -136,7 +136,7 @@ Whether you are prototyping your next idea or scaling a production app, Appwrite ## Resources * [Appwrite documentation](https://appwrite.io/docs) -* [Appwrite AI products](https://appwrite.io/docs/products/ai) +* [Appwrite Functions](https://appwrite.io/docs/products/functions) * [Appwrite integrations](https://appwrite.io/integrations) * [Appwrite quick start guides](https://appwrite.io/docs/quick-starts) * [Appwrite on GitHub](https://github.com/appwrite/appwrite) From 997e4e0c9e3bc2bf64f4940481a0fb4934c8effa Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 26 Jun 2026 16:37:51 +0530 Subject: [PATCH 29/61] Address React library PR review feedback Bump blog and changelog date to 2026-06-26, add four generic FAQs (beta status, React Native, cookie/redirect customization, magic URL/phone). Restructure hooks reference: drop bare "Returns:" labels, add one-line intros, split sign-in/up/out parameter tables into ### sub-headings. Wrap Next.js and TanStack Start handler examples in {% tabs %}. Grammar pass: add missing commas in provider, OAuth, session and admin client copy. --- .../+page.markdoc | 10 ++- ...{2026-06-24.markdoc => 2026-06-26.markdoc} | 2 +- .../docs/products/auth/react/+page.markdoc | 75 +++++++++++-------- 3 files changed, 52 insertions(+), 35 deletions(-) rename src/routes/changelog/(entries)/{2026-06-24.markdoc => 2026-06-26.markdoc} (97%) diff --git a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc index d7641121c91..68d1cd5926c 100644 --- a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc +++ b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc @@ -2,7 +2,7 @@ layout: post title: "Announcing the Appwrite React library" description: A small set of React hooks and SSR adapters that take the busywork out of wiring Appwrite Auth into Vite, Next.js, and TanStack Start apps. -date: 2026-06-24 +date: 2026-06-26 cover: /images/blog/announcing-appwrite-react-library/cover.avif timeToRead: 5 author: atharva @@ -16,8 +16,16 @@ faqs: answer: 'React 18 and React 19, on both client-rendered apps and SSR frameworks. Next.js 15+ and TanStack Start are supported out of the box.' - question: 'How does SSR auth work under the hood?' answer: 'You mount one handler route per framework. The handler creates sessions with a server API key and writes an HTTP-only cookie. On the server, helpers read the cookie and return the user; on the client, the same cookie hydrates the Web SDK so hooks return the user without an extra round trip.' + - question: 'Is the library production ready?' + answer: 'The first release ships as `beta`. The auth surface is stable and used internally, but the public API may receive small adjustments before `1.0`. Pin the version you install and watch the [changelog](https://github.com/appwrite/sdk-for-react/releases) for breaking changes.' - question: 'Does the library cover more than authentication?' answer: 'Not yet. The first release focuses on the auth surface (sign-up, sign-in, sign-out, OAuth, current user). Database and storage hooks are on the roadmap.' + - question: 'Does the library work with React Native?' + answer: 'No. React Native apps should keep using the dedicated [Appwrite React Native SDK](/docs/sdks), which is built around the platform''s native session and storage primitives. The React library targets web React, on both client-rendered and SSR frameworks.' + - question: 'How do I customize cookies and OAuth redirects?' + answer: 'The SSR handler accepts `cookieName`, `cookieOptions`, and `redirects.success` / `redirects.failure` options. You can rename the session cookie, scope it to a parent domain, or change where users land after a successful or failed OAuth flow. See the [handler options reference](/docs/products/auth/react#handler-options).' + - question: 'Does it support magic URL, phone, or other authentication methods?' + answer: 'The current hooks cover email and password sign-in, sign-up, sign-out, and OAuth. For magic URL, phone, anonymous, or JWT flows, drop down to the Web SDK via `useAppwrite().account` and call the method directly. More dedicated hooks are planned.' - question: 'Where do I start?' answer: 'Pick the framework you are using: [Vite React](/docs/quick-starts/react), [Next.js](/docs/quick-starts/nextjs), or [TanStack Start](/docs/quick-starts/tanstack-start). Each quickstart walks through install, configuration, and a working sign-up flow.' --- diff --git a/src/routes/changelog/(entries)/2026-06-24.markdoc b/src/routes/changelog/(entries)/2026-06-26.markdoc similarity index 97% rename from src/routes/changelog/(entries)/2026-06-24.markdoc rename to src/routes/changelog/(entries)/2026-06-26.markdoc index 00dd5d62cf3..6d7a9a77b9e 100644 --- a/src/routes/changelog/(entries)/2026-06-24.markdoc +++ b/src/routes/changelog/(entries)/2026-06-26.markdoc @@ -1,7 +1,7 @@ --- layout: changelog title: 'Announcing the Appwrite React library' -date: 2026-06-24 +date: 2026-06-26 cover: /images/blog/announcing-appwrite-react-library/cover.avif --- diff --git a/src/routes/docs/products/auth/react/+page.markdoc b/src/routes/docs/products/auth/react/+page.markdoc index 9af7ceaeaa5..6978f21161d 100644 --- a/src/routes/docs/products/auth/react/+page.markdoc +++ b/src/routes/docs/products/auth/react/+page.markdoc @@ -67,7 +67,7 @@ In an SSR app, pass an `ssr` prop with the session secret read from the server-s ``` -When `ssr` is set, sign-in, sign-up, and sign-out mutations route through your handler. The underlying Web SDK is hydrated with the session secret on first render so authenticated reads do not need a round trip. +When `ssr` is set, sign-in, sign-up, and sign-out mutations route through your handler. The underlying Web SDK is hydrated with the session secret on first render, so authenticated reads do not need a round trip. # Hooks {% #hooks %} @@ -75,14 +75,14 @@ The library exports one combined hook and four focused mutation hooks. All hooks ## useAuth {% #use-auth %} +The primary hook for most apps. It bundles the current user, loading and error state, and handles for sign-in, sign-up, and sign-out into a single return value. + ```tsx import { useAuth } from "@appwrite.io/react"; const { user, isLoading, error, refresh, signIn, signUp, signOut } = useAuth(); ``` -Returns: - | Field | Type | Description | | --- | --- | --- | | `user` | `Models.User \| null \| undefined` | The current user, or `null` if signed out. `undefined` while loading. | @@ -95,14 +95,14 @@ Returns: ## useUser {% #use-user %} +Read-only access to the current authenticated user. Use it in components that only need to display user state and do not trigger auth mutations. + ```tsx import { useUser } from "@appwrite.io/react"; const { user, isLoading, error, refresh } = useUser(); ``` -Returns: - | Field | Type | Description | | --- | --- | --- | | `user` | `Models.User \| null \| undefined` | The current user, or `null` if signed out. `undefined` while loading. | @@ -112,15 +112,12 @@ Returns: ## useSignIn {% #use-sign-in %} +Email and password and OAuth sign-in, with pending and error state scoped to the email and password flow. + ```tsx const { emailPassword, oAuth, isPending, error } = useSignIn(); - -emailPassword({ email, password, onSuccess, onError }); -oAuth({ provider: OAuthProvider.Google, successUrl, failureUrl, scopes }); ``` -Returns: - | Field | Type | Description | | --- | --- | --- | | `emailPassword` | `function` | Trigger an email and password sign-in. | @@ -128,7 +125,11 @@ Returns: | `isPending` | `boolean` | True while an email and password sign-in is in flight. | | `error` | `Error \| null` | Error from the last email and password sign-in attempt. | -Parameters for `emailPassword`: +### Email and password {% #use-sign-in-email-password %} + +```tsx +emailPassword({ email, password, onSuccess, onError }); +``` | Parameter | Required | Description | | --- | --- | --- | @@ -137,7 +138,11 @@ Parameters for `emailPassword`: | `onSuccess` | No | Callback invoked with the signed-in user. | | `onError` | No | Callback invoked with the thrown error. | -Parameters for `oAuth`: +### OAuth {% #use-sign-in-oauth %} + +```tsx +oAuth({ provider: OAuthProvider.Google, successUrl, failureUrl, scopes }); +``` | Parameter | Required | Description | | --- | --- | --- | @@ -147,25 +152,27 @@ Parameters for `oAuth`: | `scopes` | No | Provider-specific OAuth scopes to request. | | `onError` | No | Callback invoked if the request fails before redirect. | -In SSR mode the success URL is fixed to the handler callback. The final redirect after that callback is controlled by the `redirects.success` config on the handler. +In SSR mode, the success URL is fixed to the handler callback. The final redirect after that callback is controlled by the `redirects.success` config on the handler. ## useSignUp {% #use-sign-up %} +Create an account and start a session in one call. The hook also surfaces pending and error state for the in-flight request. + ```tsx const { emailPassword, isPending, error } = useSignUp(); - -emailPassword({ email, password, name, userId, onSuccess, onError }); ``` -Returns: - | Field | Type | Description | | --- | --- | --- | | `emailPassword` | `function` | Create an account with email and password, then sign the user in. | | `isPending` | `boolean` | True while the sign-up is in flight. | | `error` | `Error \| null` | Error from the last sign-up attempt. | -Parameters for `emailPassword`: +### Email and password {% #use-sign-up-email-password %} + +```tsx +emailPassword({ email, password, name, userId, onSuccess, onError }); +``` | Parameter | Required | Description | | --- | --- | --- | @@ -178,21 +185,23 @@ Parameters for `emailPassword`: ## useSignOut {% #use-sign-out %} +End the current session, drop cached auth queries, and reset the local Web SDK client. + ```tsx const { signOut, isPending, error } = useSignOut(); - -signOut({ onSuccess, onError }); ``` -Returns: - | Field | Type | Description | | --- | --- | --- | | `signOut` | `function` | End the current user's session. | | `isPending` | `boolean` | True while the sign-out is in flight. | | `error` | `Error \| null` | Error from the last sign-out attempt. | -Parameters for `signOut`: +### Sign out {% #use-sign-out-method %} + +```tsx +signOut({ onSuccess, onError }); +``` | Parameter | Required | Description | | --- | --- | --- | @@ -203,16 +212,14 @@ After a successful sign-out, all cached auth queries are dropped and the local W ## useAppwrite {% #use-appwrite %} +Escape hatch to the underlying provider context. Use it when you need direct access to a Web SDK service the higher-level hooks do not wrap (`tablesDB`, `storage`, `messaging`, `realtime`, and so on). + ```tsx import { useAppwrite } from "@appwrite.io/react"; const { client, account, tablesDB, storage, teams, ssr } = useAppwrite(); ``` -Returns the underlying provider context with every Appwrite Web SDK service instance bound to the configured client. Use it when you need direct access to a service the higher-level hooks do not wrap (`tablesDB`, `storage`, `messaging`, `realtime`, and so on). - -Returns: - | Field | Type | Description | | --- | --- | --- | | `client` | `Client` | The Appwrite Web SDK `Client` configured by the provider. | @@ -259,7 +266,7 @@ Both return an object with: ## Session client {% #session-client %} -For per-request operations scoped to the current user (reading their data, calling APIs on their behalf) call `createSessionClient` from the framework helper. It returns a `node-appwrite` client already authenticated with the session cookie, ready to use in server components, loaders, and server functions. +For per-request operations scoped to the current user (reading their data, calling APIs on their behalf), call `createSessionClient` from the framework helper. It returns a `node-appwrite` client already authenticated with the session cookie, ready to use in server components, loaders, and server functions. ```ts import { createNextServerHelpers } from "@appwrite.io/react/server/next"; @@ -278,7 +285,7 @@ if (session) { ## Admin client {% #admin-client %} -For privileged operations (creating users, listing sessions, managing teams) call `createAdminClient` on the framework helper. Pass `apiKey` in the helper config to enable it, then call the method anywhere on the server. The returned object exposes every `node-appwrite` service: `account`, `users`, `tablesDB`, `storage`, `teams`, `functions`, `messaging`, and more. +For privileged operations (creating users, listing sessions, managing teams), call `createAdminClient` on the framework helper. Pass `apiKey` in the helper config to enable it, then call the method anywhere on the server. The returned object exposes every `node-appwrite` service: `account`, `users`, `tablesDB`, `storage`, `teams`, `functions`, `messaging`, and more. ```ts import { createNextServerHelpers } from "@appwrite.io/react/server/next"; @@ -313,8 +320,8 @@ Never import any `@appwrite.io/react/server/*` module from client code: the entr The SSR mutations (`sign-in`, `sign-up`, `sign-out`, `oauth/callback`, `oauth/failure`) live behind a handler route you mount once per app. The handler reads the request, talks to Appwrite with the server API key, and writes the session cookie back. -## Next.js {% #handler-next %} - +{% tabs %} +{% tabsitem #handler-next title="Next.js" %} ```ts // app/api/appwrite/[...appwrite]/route.ts import { createAppwriteHandlers } from "@appwrite.io/react/handlers/next"; @@ -326,9 +333,9 @@ export const { GET, POST } = createAppwriteHandlers({ basePath: "/api/appwrite", }); ``` +{% /tabsitem %} -## TanStack Start {% #handler-tanstack %} - +{% tabsitem #handler-tanstack title="TanStack Start" %} ```ts // src/routes/api/appwrite/$.ts import { createFileRoute } from "@tanstack/react-router"; @@ -345,6 +352,8 @@ export const Route = createFileRoute("/api/appwrite/$")({ }, }); ``` +{% /tabsitem %} +{% /tabs %} ## Cookie and redirect options {% #handler-options %} From 5b72dc8a9390d69ed90e0d8cd1d81520f5f646ab Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 26 Jun 2026 16:40:28 +0530 Subject: [PATCH 30/61] Swap production-ready FAQ for generic ones Drop the beta/production-ready FAQ. Add three generic FAQs in its place: open source repo + license, TypeScript support, where to report bugs or request features. --- .../post/announcing-appwrite-react-library/+page.markdoc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc index 68d1cd5926c..71b56891ab9 100644 --- a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc +++ b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc @@ -16,16 +16,20 @@ faqs: answer: 'React 18 and React 19, on both client-rendered apps and SSR frameworks. Next.js 15+ and TanStack Start are supported out of the box.' - question: 'How does SSR auth work under the hood?' answer: 'You mount one handler route per framework. The handler creates sessions with a server API key and writes an HTTP-only cookie. On the server, helpers read the cookie and return the user; on the client, the same cookie hydrates the Web SDK so hooks return the user without an extra round trip.' - - question: 'Is the library production ready?' - answer: 'The first release ships as `beta`. The auth surface is stable and used internally, but the public API may receive small adjustments before `1.0`. Pin the version you install and watch the [changelog](https://github.com/appwrite/sdk-for-react/releases) for breaking changes.' + - question: 'Is the source code open?' + answer: 'Yes. The library lives in the [appwrite/sdk-for-react](https://github.com/appwrite/sdk-for-react) repository on GitHub under the BSD-3-Clause license, like the rest of the Appwrite SDKs.' - question: 'Does the library cover more than authentication?' answer: 'Not yet. The first release focuses on the auth surface (sign-up, sign-in, sign-out, OAuth, current user). Database and storage hooks are on the roadmap.' - question: 'Does the library work with React Native?' answer: 'No. React Native apps should keep using the dedicated [Appwrite React Native SDK](/docs/sdks), which is built around the platform''s native session and storage primitives. The React library targets web React, on both client-rendered and SSR frameworks.' + - question: 'Is the library written in TypeScript?' + answer: 'Yes. Every hook, provider, server helper, and handler ships with full TypeScript types. Plain JavaScript projects work too, the types are simply ignored.' - question: 'How do I customize cookies and OAuth redirects?' answer: 'The SSR handler accepts `cookieName`, `cookieOptions`, and `redirects.success` / `redirects.failure` options. You can rename the session cookie, scope it to a parent domain, or change where users land after a successful or failed OAuth flow. See the [handler options reference](/docs/products/auth/react#handler-options).' - question: 'Does it support magic URL, phone, or other authentication methods?' answer: 'The current hooks cover email and password sign-in, sign-up, sign-out, and OAuth. For magic URL, phone, anonymous, or JWT flows, drop down to the Web SDK via `useAppwrite().account` and call the method directly. More dedicated hooks are planned.' + - question: 'Where do I report bugs or request features?' + answer: 'Open an issue on [appwrite/sdk-for-react](https://github.com/appwrite/sdk-for-react/issues), or drop into the [Appwrite Discord](https://appwrite.io/discord) to discuss it with the team and community first.' - question: 'Where do I start?' answer: 'Pick the framework you are using: [Vite React](/docs/quick-starts/react), [Next.js](/docs/quick-starts/nextjs), or [TanStack Start](/docs/quick-starts/tanstack-start). Each quickstart walks through install, configuration, and a working sign-up flow.' --- From f4910ac47c5dc8b132cd820303afd95c736ec1a5 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 26 Jun 2026 17:24:22 +0530 Subject: [PATCH 31/61] Apply suggestions from code review Co-authored-by: Atharva Deosthale --- .../+page.markdoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc b/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc index 0ed36f1bf8d..6f69f988e76 100644 --- a/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc +++ b/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc @@ -135,9 +135,9 @@ Whether you are prototyping your next idea or scaling a production app, Appwrite ## Resources -* [Appwrite documentation](https://appwrite.io/docs) -* [Appwrite Functions](https://appwrite.io/docs/products/functions) -* [Appwrite integrations](https://appwrite.io/integrations) -* [Appwrite quick start guides](https://appwrite.io/docs/quick-starts) +* [Appwrite documentation](/docs) +* [Appwrite Functions](/docs/products/functions) +* [Appwrite integrations](/integrations) +* [Appwrite quick start guides](/docs/quick-starts) * [Appwrite on GitHub](https://github.com/appwrite/appwrite) * [Join the Appwrite Discord](https://appwrite.io/discord) \ No newline at end of file From 3bb1edd8c2d8983dacfe7dacbd56e2aa7c891b8c Mon Sep 17 00:00:00 2001 From: Aishwari Pahwa Date: Fri, 26 Jun 2026 17:34:12 +0530 Subject: [PATCH 32/61] Update +page.markdoc --- .../+page.markdoc | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc b/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc index 6f69f988e76..e8b4a778371 100644 --- a/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc +++ b/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc @@ -70,19 +70,6 @@ A **CI/CD pipeline** is the automated sequence of steps that code passes through Each stage acts as a gate: if a step fails, the pipeline stops and the team is notified, so broken code never reaches users. Many pipelines also include extra stages for security scanning, performance checks, and approvals. -# Continuous delivery vs continuous deployment: What's the difference? - -This is the most common point of confusion in CI/CD, so it's worth being precise. Both keep your software in a constantly releasable state. The only difference is the final step to production. - -| Aspect | Continuous delivery | Continuous deployment | -| --------------------- | ------------------------------ | ----------------------------------- | -| Release to production | Manual approval | Fully automatic | -| Human gate | Yes, a person clicks deploy | No gate | -| Confidence required | High | Very high | -| Best for | Regulated or cautious releases | Fast-moving teams with strong tests | - -Many teams start with continuous delivery to keep a human in the loop, then move to continuous deployment as their test coverage and confidence grow. - # Popular CI/CD tools A range of tools automate CI/CD pipelines, and most integrate directly with your code repository: @@ -140,4 +127,4 @@ Whether you are prototyping your next idea or scaling a production app, Appwrite * [Appwrite integrations](/integrations) * [Appwrite quick start guides](/docs/quick-starts) * [Appwrite on GitHub](https://github.com/appwrite/appwrite) -* [Join the Appwrite Discord](https://appwrite.io/discord) \ No newline at end of file +* [Join the Appwrite Discord](https://appwrite.io/discord) From 7e662f4ae4ae32a767e463133cb7b3428f12b99c Mon Sep 17 00:00:00 2001 From: Aishwari Pahwa Date: Fri, 26 Jun 2026 18:01:54 +0530 Subject: [PATCH 33/61] Update +page.markdoc --- .../+page.markdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc b/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc index e8b4a778371..cd19d3c57fb 100644 --- a/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc +++ b/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc @@ -116,9 +116,9 @@ CI/CD is the practice of automating the path from code to production, combining # Start building -Appwrite is open-source, self-hostable, and built for developers who want to ship fast without surrendering control. Recent releases have added [MongoDB support, Appwrite 1.9.0, realtime upgrades, and new AI tooling](https://dev.to/appwrite/april-product-update-mongodb-support-appwrite-190-realtime-upgrades-and-ai-tooling-1eg6), with [more landing every few weeks](https://dev.to/appwrite/may-product-update-presences-api-rust-runtime-7x-faster-storage-uploads-and-more-9h5). We post weekly roundups of product announcements, AI updates, and [developer insights](https://dev.to/appwrite/weekly-roundup-presences-api-git-deployment-triggers-and-ai-updates-58lj) on the [Appwrite blog](https://appwrite.io/blog) and across our developer channels, so follow along wherever you read. +Appwrite is open-source, self-hostable, and built for developers who want to ship fast without surrendering control. -Whether you are prototyping your next idea or scaling a production app, Appwrite gives you auth, databases, storage, functions, and real-time in one place, all open-source. [Sign up for Appwrite Cloud](https://cloud.appwrite.io/) or spin up a self-hosted instance in minutes, and give your next build a real backend to grow on. +Whether you are prototyping your next idea or scaling a production app, Appwrite gives you Auth, Databases, Storage, Sites, Functions, and Realtime in one open-source platform. [Sign up for Appwrite Cloud](https://cloud.appwrite.io/) or spin up a self-hosted instance in minutes, and give your next build a real backend to grow on. ## Resources From 0c19e0b9dca9edff002eea53f2fc68c2f2b263e2 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 26 Jun 2026 18:04:23 +0530 Subject: [PATCH 34/61] Tab the useSignIn email and OAuth parameters Wrap the per-method parameter blocks for emailPassword and oAuth in {% tabs %} so readers see one method at a time instead of stacked sub-sections. --- src/routes/docs/products/auth/react/+page.markdoc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/routes/docs/products/auth/react/+page.markdoc b/src/routes/docs/products/auth/react/+page.markdoc index 6978f21161d..ec59e54bc29 100644 --- a/src/routes/docs/products/auth/react/+page.markdoc +++ b/src/routes/docs/products/auth/react/+page.markdoc @@ -125,8 +125,8 @@ const { emailPassword, oAuth, isPending, error } = useSignIn(); | `isPending` | `boolean` | True while an email and password sign-in is in flight. | | `error` | `Error \| null` | Error from the last email and password sign-in attempt. | -### Email and password {% #use-sign-in-email-password %} - +{% tabs %} +{% tabsitem #use-sign-in-email-password title="Email and password" %} ```tsx emailPassword({ email, password, onSuccess, onError }); ``` @@ -137,9 +137,9 @@ emailPassword({ email, password, onSuccess, onError }); | `password` | Yes | User's password. | | `onSuccess` | No | Callback invoked with the signed-in user. | | `onError` | No | Callback invoked with the thrown error. | +{% /tabsitem %} -### OAuth {% #use-sign-in-oauth %} - +{% tabsitem #use-sign-in-oauth title="OAuth" %} ```tsx oAuth({ provider: OAuthProvider.Google, successUrl, failureUrl, scopes }); ``` @@ -153,6 +153,8 @@ oAuth({ provider: OAuthProvider.Google, successUrl, failureUrl, scopes }); | `onError` | No | Callback invoked if the request fails before redirect. | In SSR mode, the success URL is fixed to the handler callback. The final redirect after that callback is controlled by the `redirects.success` config on the handler. +{% /tabsitem %} +{% /tabs %} ## useSignUp {% #use-sign-up %} From dbdccdc042b23b1259a686bc467ead3d7d70bb34 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 26 Jun 2026 18:44:06 +0530 Subject: [PATCH 35/61] Trim blog FAQs to generic auth-library questions Drop the FAQs that were specific to the library's design or roadmap. Keep version support, open source, supported auth methods, and where to start. Add two generic FAQs explaining what an authentication library is and why teams reach for one. --- .../+page.markdoc | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc index 71b56891ab9..5e869c472b6 100644 --- a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc +++ b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc @@ -8,28 +8,16 @@ timeToRead: 5 author: atharva category: announcement, authentication faqs: - - question: 'What is the Appwrite React library?' - answer: 'It is an official React package that wraps the Appwrite Web SDK with a `Provider` and hooks for auth state. It also ships SSR adapters for Next.js and TanStack Start so the same hooks work in server-rendered apps. See the [React library docs](/docs/products/auth/react).' - - question: 'Do I need this if I already use the Appwrite Web SDK?' - answer: 'No, the Web SDK alone still works. The library is for teams who want pre-built hooks, less boilerplate around session hydration, and a turnkey SSR auth flow. If your app is small or fully client-rendered, the Web SDK on its own is fine.' + - question: 'What is an authentication library?' + answer: 'An authentication library is a package that handles the common pieces of user sign-up, sign-in, sign-out, session management, and OAuth on your behalf, so you do not have to wire each one up from scratch in every project.' + - question: 'Why use an authentication library instead of building auth yourself?' + answer: 'Auth touches sessions, cookies, password handling, OAuth callbacks, and a handful of edge cases that are easy to get subtly wrong. A library gives you a tested implementation of those pieces and a small, consistent API on top, so you spend your time on product features instead of re-implementing the same flows.' - question: 'Which React versions are supported?' answer: 'React 18 and React 19, on both client-rendered apps and SSR frameworks. Next.js 15+ and TanStack Start are supported out of the box.' - - question: 'How does SSR auth work under the hood?' - answer: 'You mount one handler route per framework. The handler creates sessions with a server API key and writes an HTTP-only cookie. On the server, helpers read the cookie and return the user; on the client, the same cookie hydrates the Web SDK so hooks return the user without an extra round trip.' - question: 'Is the source code open?' answer: 'Yes. The library lives in the [appwrite/sdk-for-react](https://github.com/appwrite/sdk-for-react) repository on GitHub under the BSD-3-Clause license, like the rest of the Appwrite SDKs.' - - question: 'Does the library cover more than authentication?' - answer: 'Not yet. The first release focuses on the auth surface (sign-up, sign-in, sign-out, OAuth, current user). Database and storage hooks are on the roadmap.' - - question: 'Does the library work with React Native?' - answer: 'No. React Native apps should keep using the dedicated [Appwrite React Native SDK](/docs/sdks), which is built around the platform''s native session and storage primitives. The React library targets web React, on both client-rendered and SSR frameworks.' - - question: 'Is the library written in TypeScript?' - answer: 'Yes. Every hook, provider, server helper, and handler ships with full TypeScript types. Plain JavaScript projects work too, the types are simply ignored.' - - question: 'How do I customize cookies and OAuth redirects?' - answer: 'The SSR handler accepts `cookieName`, `cookieOptions`, and `redirects.success` / `redirects.failure` options. You can rename the session cookie, scope it to a parent domain, or change where users land after a successful or failed OAuth flow. See the [handler options reference](/docs/products/auth/react#handler-options).' - question: 'Does it support magic URL, phone, or other authentication methods?' answer: 'The current hooks cover email and password sign-in, sign-up, sign-out, and OAuth. For magic URL, phone, anonymous, or JWT flows, drop down to the Web SDK via `useAppwrite().account` and call the method directly. More dedicated hooks are planned.' - - question: 'Where do I report bugs or request features?' - answer: 'Open an issue on [appwrite/sdk-for-react](https://github.com/appwrite/sdk-for-react/issues), or drop into the [Appwrite Discord](https://appwrite.io/discord) to discuss it with the team and community first.' - question: 'Where do I start?' answer: 'Pick the framework you are using: [Vite React](/docs/quick-starts/react), [Next.js](/docs/quick-starts/nextjs), or [TanStack Start](/docs/quick-starts/tanstack-start). Each quickstart walks through install, configuration, and a working sign-up flow.' --- From 9e2a2d0077f958fc7dc7099642cfb090a942f3b9 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 26 Jun 2026 19:17:10 +0530 Subject: [PATCH 36/61] Revert "ci: move production deploy to declarative setup, target default.yaml" --- .github/workflows/production.yml | 78 ++++++++++++++++++-------------- .github/workflows/staging.yml | 19 ++++---- 2 files changed, 51 insertions(+), 46 deletions(-) diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 07a6a2af535..2a3b7b22780 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -6,28 +6,27 @@ on: workflow_dispatch: env: - ENVIRONMENT: production - PROJECT: website - DECLARATIVE_OWNER: appwrite-labs - DECLARATIVE_REPOSITORY: assets-applications TAG: ${{ github.event.release.tag_name || github.sha }} + STACK_FILE: docker/production.yml + REPOSITORY: website + REGISTRY_USERNAME: christyjacob4 jobs: build: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + uses: actions/checkout@v4 - name: Login to DockerHub - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 + uses: docker/build-push-action@v6 with: context: . push: true @@ -50,40 +49,49 @@ jobs: "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" "SENTRY_RELEASE=${{ github.event.release.tag_name }}" - deploy: + deploy_kubernetes: if: github.event_name != 'release' || !contains(github.event.release.tag_name, '-rc') + strategy: + matrix: + region: [{ full: fra1, short: fra }] needs: build runs-on: ubuntu-latest - concurrency: - group: declarative-deploy-website - cancel-in-progress: false steps: - - name: Get token for ${{ env.DECLARATIVE_REPOSITORY }} - id: app-token - uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 + - name: Checkout the repo + uses: actions/checkout@v4 + - name: Install Kubectl + uses: azure/setup-kubectl@v4 + - name: Install Helm + uses: azure/setup-helm@v4 + - name: Install doctl + uses: digitalocean/action-doctl@v2 with: - app-id: ${{ vars.DECLARATIVE_DEPLOYMENT_GITHUB_APP_ID }} - private-key: ${{ secrets.DECLARATIVE_DEPLOYMENT_GITHUB_APP_PRIVATE_KEY }} - owner: ${{ env.DECLARATIVE_OWNER }} - repositories: ${{ env.DECLARATIVE_REPOSITORY }} + token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + - name: Save DigitalOcean kubeconfig with short-lived credentials + run: doctl kubernetes cluster kubeconfig save --expiry-seconds 600 assets-${{ matrix.region.full }}-prod - - name: Checkout ${{ env.DECLARATIVE_REPOSITORY }} - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - repository: ${{ env.DECLARATIVE_OWNER }}/${{ env.DECLARATIVE_REPOSITORY }} - token: ${{ steps.app-token.outputs.token }} + - name: Ensure namespaces exist + run: | + kubectl create namespace website --dry-run=client -o yaml | kubectl apply -f - - - name: Update image tag - run: yq -i '.website.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml + - name: Create docker pull secret + run: | + kubectl -n website create secret docker-registry ghcr \ + --docker-server=ghcr.io \ + --docker-username=${{ secrets.GHCR_USERNAME }} \ + --docker-password=${{ secrets.GHCR_TOKEN }} \ + --docker-email=ci@appwrite.io \ + --dry-run=client -o yaml | kubectl apply -f - + + - name: Create app secrets + run: | + kubectl -n website create secret generic website-secrets \ + --from-literal=STATSIG_SERVER_SECRET='${{ secrets.STATSIG_SERVER_SECRET }}' \ + --dry-run=client -o yaml | kubectl apply -f - - - name: Commit and push + - name: Deploy run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml - if git diff --cached --quiet; then - echo "No changes to commit" - else - git commit -m "chore(${{ env.ENVIRONMENT }}): ${{ env.PROJECT }} image tag to ${{ env.TAG }}" - git push - fi + helm upgrade --install --namespace website website deploy/website/ \ + --values deploy/website/environments/production/${{ matrix.region.full }}.values.yaml \ + --set imagePullSecret='ghcr' \ + --set version=${{ env.TAG }} diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index 3736ba9d148..a581c48fbf5 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -25,24 +25,24 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@v6 - name: Login to GitHub Container Registry - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY_GITHUB }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker Hub - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY_DOCKERHUB }} username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 + uses: docker/build-push-action@v6 with: context: . push: true @@ -69,13 +69,10 @@ jobs: deploy: needs: build runs-on: ubuntu-latest - concurrency: - group: declarative-deploy-website - cancel-in-progress: false steps: - name: Get token for ${{ env.DECLARATIVE_REPOSITORY }} id: app-token - uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 + uses: actions/create-github-app-token@v2 with: app-id: ${{ vars.DECLARATIVE_DEPLOYMENT_GITHUB_APP_ID }} private-key: ${{ secrets.DECLARATIVE_DEPLOYMENT_GITHUB_APP_PRIVATE_KEY }} @@ -83,19 +80,19 @@ jobs: repositories: ${{ env.DECLARATIVE_REPOSITORY }} - name: Checkout ${{ env.DECLARATIVE_REPOSITORY }} - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@v6 with: repository: ${{ env.DECLARATIVE_OWNER }}/${{ env.DECLARATIVE_REPOSITORY }} token: ${{ steps.app-token.outputs.token }} - name: Update image tag - run: yq -i '.website.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml + run: yq -i '.website.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/fra1.yaml - name: Commit and push run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml + git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/fra1.yaml if git diff --cached --quiet; then echo "No changes to commit" else From a8b400c13f1d507b2cb345f40fe231fddca498f9 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 26 Jun 2026 21:33:03 +0530 Subject: [PATCH 37/61] Add Appwrite 1.9.5 self-hosted release blog, changelog, and docs updates - New blog post and changelog entry for the Appwrite 1.9.5 self-hosted release (dated 2026-06-29) - Bump self-hosting install docs to 1.9.5 and add the 1.9.5 SDK compatibility matrix rows - Update the compose generator to 1.9.5 (console 8.7.5, executor 0.25.1/exc1, worker-executions, migration host + open runtimes NFT env) --- .optimize-cache.json | 1 + .../compose-generator/composeData.ts | 78 +++++++++---- .../+page.markdoc | 107 ++++++++++++++++++ .../changelog/(entries)/2026-06-29.markdoc | 28 +++++ .../configuration/databases/+page.markdoc | 6 +- .../self-hosting/installation/+page.markdoc | 27 ++++- .../cover.avif | Bin 0 -> 12700 bytes 7 files changed, 218 insertions(+), 29 deletions(-) create mode 100644 src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc create mode 100644 src/routes/changelog/(entries)/2026-06-29.markdoc create mode 100644 static/images/blog/appwrite-1-9-5-self-hosted-release/cover.avif diff --git a/.optimize-cache.json b/.optimize-cache.json index f926af4a597..d39862c4f80 100644 --- a/.optimize-cache.json +++ b/.optimize-cache.json @@ -258,6 +258,7 @@ "static/images/blog/apply-appwrite-how/cover.png": "d23f45ced245b42c8712c021f5d2068c17aebd94fd049cb90222cb9647a41a4a", "static/images/blog/appwrite-1-8-0-self-hosted-release/cover.png": "c15a9d88ccd16c2dc8333dc74e715e1f4a6c7818d3b4a05f4d68342eacdc0523", "static/images/blog/appwrite-1-8-1-self-hosted-release/cover.png": "82f0a396c56b6b299b24133079acc6a317c66b2bf02fd91f4862bd3be0f8f373", + "static/images/blog/appwrite-1-9-5-self-hosted-release/cover.png": "f5958ba97aa507888c54c11ba156bf8a4e0643d129ed900ef1c83915efa31e88", "static/images/blog/appwrite-1.5-now-available-on-cloud/cloud15.png": "a1df7388572a9f08d0e315e4b6bc8c9464c1418768e7efbec22758fd728eb970", "static/images/blog/appwrite-auth-methods/cover.png": "361513d8b59de8fde7b294dcc6688aada30c46e11933070c529733e486784690", "static/images/blog/appwrite-backups-and-restores/cover.png": "369b5d91f3dc515e7fb86588f8871aa5ffd788b40023e8373ac694840479c1ab", diff --git a/src/lib/components/compose-generator/composeData.ts b/src/lib/components/compose-generator/composeData.ts index ba23c21d4f4..2334d50881b 100644 --- a/src/lib/components/compose-generator/composeData.ts +++ b/src/lib/components/compose-generator/composeData.ts @@ -146,7 +146,7 @@ services: - appwrite appwrite: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 container_name: appwrite <<: *x-logging restart: unless-stopped @@ -290,7 +290,7 @@ services: appwrite-console: <<: *x-logging container_name: appwrite-console - image: appwrite/console:7.8.26 + image: appwrite/console:8.7.5 restart: unless-stopped networks: - appwrite @@ -310,7 +310,7 @@ services: - traefik.http.routers.appwrite_console_https.tls=true appwrite-realtime: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: realtime container_name: appwrite-realtime <<: *x-logging @@ -356,7 +356,7 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-audits: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-audits <<: *x-logging container_name: appwrite-worker-audits @@ -385,7 +385,7 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-webhooks: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-webhooks <<: *x-logging container_name: appwrite-worker-webhooks @@ -416,7 +416,7 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-deletes: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-deletes <<: *x-logging container_name: appwrite-worker-deletes @@ -482,7 +482,7 @@ services: - _APP_EMAIL_CERTIFICATES appwrite-worker-databases: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-databases <<: *x-logging container_name: appwrite-worker-databases @@ -511,7 +511,7 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-builds: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-builds <<: *x-logging container_name: appwrite-worker-builds @@ -554,6 +554,7 @@ services: - _APP_COMPUTE_CPUS - _APP_COMPUTE_MEMORY - _APP_COMPUTE_SIZE_LIMIT + - _APP_OPEN_RUNTIMES_NFT - _APP_OPTIONS_FORCE_HTTPS - _APP_OPTIONS_ROUTER_FORCE_HTTPS - _APP_DOMAIN @@ -582,7 +583,7 @@ services: - _APP_DOMAIN_SITES appwrite-worker-certificates: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-certificates <<: *x-logging container_name: appwrite-worker-certificates @@ -621,8 +622,36 @@ services: - _APP_DB_PASS - _APP_LOGGING_CONFIG + appwrite-worker-executions: + image: appwrite/appwrite:1.9.5 + entrypoint: worker-executions + <<: *x-logging + container_name: appwrite-worker-executions + restart: unless-stopped + networks: + - appwrite + depends_on: + redis: + condition: service_healthy + __DB_SERVICE__: + condition: service_healthy + environment: + - _APP_ENV + - _APP_WORKER_PER_CORE + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS + - _APP_DB_ADAPTER + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + - _APP_LOGGING_CONFIG + appwrite-worker-functions: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-functions <<: *x-logging container_name: appwrite-worker-functions @@ -665,7 +694,7 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-mails: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-mails <<: *x-logging container_name: appwrite-worker-mails @@ -703,7 +732,7 @@ services: - _APP_OPTIONS_FORCE_HTTPS appwrite-worker-messaging: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-messaging <<: *x-logging container_name: appwrite-worker-messaging @@ -758,7 +787,7 @@ services: - _APP_STORAGE_WASABI_BUCKET appwrite-worker-migrations: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-migrations <<: *x-logging container_name: appwrite-worker-migrations @@ -796,7 +825,7 @@ services: - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET appwrite-task-maintenance: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: maintenance <<: *x-logging container_name: appwrite-task-maintenance @@ -839,7 +868,7 @@ services: - _APP_MAINTENANCE_RETENTION_SCHEDULES appwrite-task-stats-resources: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 container_name: appwrite-task-stats-resources entrypoint: stats-resources <<: *x-logging @@ -871,7 +900,7 @@ services: - _APP_STATS_RESOURCES_INTERVAL appwrite-worker-stats-resources: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-stats-resources container_name: appwrite-worker-stats-resources <<: *x-logging @@ -902,7 +931,7 @@ services: - _APP_STATS_RESOURCES_INTERVAL appwrite-worker-stats-usage: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-stats-usage container_name: appwrite-worker-stats-usage <<: *x-logging @@ -933,7 +962,7 @@ services: - _APP_USAGE_AGGREGATION_INTERVAL appwrite-task-scheduler-functions: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: schedule-functions container_name: appwrite-task-scheduler-functions <<: *x-logging @@ -949,6 +978,7 @@ services: - _APP_ENV - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 + - _APP_MIGRATION_HOST - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -961,7 +991,7 @@ services: - _APP_DB_PASS appwrite-task-scheduler-executions: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: schedule-executions container_name: appwrite-task-scheduler-executions <<: *x-logging @@ -977,6 +1007,7 @@ services: - _APP_ENV - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 + - _APP_MIGRATION_HOST - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -989,7 +1020,7 @@ services: - _APP_DB_PASS appwrite-task-scheduler-messages: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: schedule-messages container_name: appwrite-task-scheduler-messages <<: *x-logging @@ -1026,12 +1057,12 @@ __ASSISTANT_BLOCK__ - appwrite openruntimes-executor: - container_name: openruntimes-executor + container_name: exc1 hostname: exc1 <<: *x-logging restart: unless-stopped stop_signal: SIGINT - image: openruntimes/executor:0.7.22 + image: openruntimes/executor:0.25.1 networks: - appwrite - runtimes @@ -1053,6 +1084,7 @@ __ASSISTANT_BLOCK__ - OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES,$_APP_SITES_RUNTIMES - OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET - OPR_EXECUTOR_RUNTIME_VERSIONS=v5 + - OPEN_RUNTIMES_NFT=$_APP_OPEN_RUNTIMES_NFT - OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG - OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE - OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY @@ -1240,6 +1272,7 @@ _APP_EXECUTOR_RUNTIME_NETWORK=appwrite_runtimes _APP_FUNCTIONS_ENVS=node-16.0,php-7.4,python-3.9,ruby-3.0 _APP_FUNCTIONS_INACTIVE_THRESHOLD=60 _APP_COMPUTE_INACTIVE_THRESHOLD=60 +_APP_OPEN_RUNTIMES_NFT=enabled DOCKERHUB_PULL_USERNAME= DOCKERHUB_PULL_PASSWORD= DOCKERHUB_PULL_EMAIL= @@ -1272,6 +1305,7 @@ _APP_GRAPHQL_INTROSPECTION=enabled _APP_GRAPHQL_MAX_BATCH_SIZE=10 _APP_GRAPHQL_MAX_COMPLEXITY=250 _APP_GRAPHQL_MAX_DEPTH=3 +_APP_MIGRATION_HOST=appwrite _APP_MIGRATIONS_FIREBASE_CLIENT_ID= _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET= _APP_ASSISTANT_OPENAI_API_KEY=__ASSISTANT_KEY__ diff --git a/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc b/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc new file mode 100644 index 00000000000..44eb39e6024 --- /dev/null +++ b/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc @@ -0,0 +1,107 @@ +--- +layout: post +title: Announcing Appwrite 1.9.5 for self-hosted deployments +description: Appwrite 1.9.5 brings the Presences API, BigInt columns, the Rust runtime, X OAuth, email policies, Bun and Deno build runtimes, Git deployment triggers, faster Storage uploads, and broader migrations to self-hosted deployments. +cover: /images/blog/appwrite-1-9-5-self-hosted-release/cover.avif +date: 2026-06-29 +timeToRead: 6 +author: chirag-aggarwal +category: announcement +featured: false +callToAction: true +faqs: + - question: "What is new in Appwrite 1.9.5 for self-hosted deployments?" + answer: "Appwrite 1.9.5 brings the Presences API, BigInt columns for [Databases](/docs/products/databases), the Rust runtime for [Functions](/docs/products/functions), X OAuth and email policies for [Auth](/docs/products/auth), Bun and Deno build runtimes and Git deployment triggers for [Sites](/docs/products/sites), faster Storage uploads with parallel chunks, and broader migration coverage." + - question: "What is the Presences API used for?" + answer: "The Presences API tracks short-lived user states such as online, away, typing, editing, or viewing. You can use it to build online indicators, typing states, collaborative editors, multiplayer features, and live activity feeds without managing presence channels yourself." + - question: "What are BigInt columns in Appwrite?" + answer: "BigInt columns store 64-bit signed integers in [Databases](/docs/products/databases). They are suited to large counters, external IDs, high-resolution timestamps, and financial values that need integer precision without floating-point rounding." + - question: "Can I block disposable or free email addresses at signup?" + answer: "Yes. Email policies in [Appwrite Auth](/docs/products/auth) let you block disposable inboxes, aliased addresses, and free email providers at user creation and on email updates, either from the Console or through any server SDK." + - question: "How do I upgrade my self-hosted instance to 1.9.5?" + answer: "Back up your data, pull the 1.9.5 image, run the upgrade command, and run the migration. Always test the upgrade on a staging environment first." +--- + +**Appwrite 1.9.5** is now available for self-hosted deployments. + +Over the past few months, we have shipped a steady stream of features across Appwrite Cloud. This release brings them to teams running Appwrite on their own infrastructure. + +Here is what is new in Appwrite 1.9.5. + +# Presences API + +The Presences API tracks short-lived user states such as online, away, typing, editing, and viewing. It gives you a managed way to build online indicators, typing states, multiplayer presence, collaborative editors, and live activity feeds, without wiring up presence channels by hand. Entries carry custom metadata and expire automatically, so stale sessions clear themselves. + +{% arrow_link href="/blog/post/announcing-presences-api" %} +Read the announcement +{% /arrow_link %} + +# BigInt columns + +Appwrite Databases now support 64-bit signed integers through the BigInt column type. BigInt is the right choice for large counters, external identifiers, high-resolution timestamps, and financial values that need integer precision without floating-point rounding. + +{% arrow_link href="/blog/post/announcing-bigint-columns" %} +Read the announcement +{% /arrow_link %} + +# Rust runtime for Functions + +Appwrite Functions now supports Rust as a first-class runtime. You can write and deploy functions in Rust, pair them with the official Appwrite Rust SDK, and use them for performance-sensitive workloads such as webhook verification, image processing, and data transformation. + +{% arrow_link href="/blog/post/announcing-rust-runtime" %} +Read the announcement +{% /arrow_link %} + +# Bun and Deno build runtimes for Sites + +Appwrite Sites can now build Node-based frameworks with Bun or Deno. You can switch the build runtime per Site from its Runtime settings, and the change applies on the next deployment. + +{% arrow_link href="/blog/post/announcing-bun-deno-runtimes" %} +Read the announcement +{% /arrow_link %} + +# Git deployment triggers + +Git deployment triggers give you control over which changes create a deployment. Use branch filters to separate production, staging, and preview workflows, and path filters so each Function or Site only deploys when relevant files change. + +{% arrow_link href="/blog/post/announcing-git-deployment-triggers" %} +Read the announcement +{% /arrow_link %} + +# X OAuth provider + +Appwrite Auth now supports signing in with X (formerly Twitter) through OAuth 2.0 with PKCE. You can enable it from the Console by adding your X app credentials, with no additional configuration in your application code. + +{% arrow_link href="/blog/post/x-oauth2-appwrite" %} +Read the announcement +{% /arrow_link %} + +# Email policies + +Email policies let you restrict which email addresses can create accounts or update their email. Block disposable inboxes to keep throwaway accounts out of your users table, and deny free providers so business products only accept corporate addresses. Each policy is an independent toggle in the Console or any server SDK. + +{% arrow_link href="/blog/post/announcing-email-policies" %} +Read the announcement +{% /arrow_link %} + +# Faster uploads with parallel chunks + +Appwrite SDKs now upload Storage file chunks in parallel. In our Node SDK benchmark, a 1.28 GB upload dropped from 4 minutes 44 seconds to under 40 seconds, a 7.10x improvement, with no API changes required. + +{% arrow_link href="/blog/post/faster-storage-uploads-parallel-chunks" %} +Read the announcement +{% /arrow_link %} + +# Improved migrations + +Migrations in 1.9.5 carry over far more than your data. Project configuration now transfers alongside it, including API keys, project variables, webhooks, OAuth providers, SMTP settings, email templates, custom domains, and security policies. Moving a project between Appwrite instances, such as from Appwrite Cloud to a self-hosted instance, now reproduces its setup instead of just its records. + +# Upgrade your self-hosted instance + +As with every Appwrite upgrade: + +- Back up your data before upgrading +- [Install or upgrade your self-hosted instance](/docs/advanced/self-hosting/production/updates#install-next-version) to **Appwrite 1.9.5** +- [Run the migration](/docs/advanced/self-hosting/production/updates#running-the-migration), even if you are upgrading from 1.9.0 + +To view the complete list of changes, fixes, and contributions, check out the full [release notes](https://github.com/appwrite/appwrite/releases/tag/1.9.5). diff --git a/src/routes/changelog/(entries)/2026-06-29.markdoc b/src/routes/changelog/(entries)/2026-06-29.markdoc new file mode 100644 index 00000000000..5973d23cb70 --- /dev/null +++ b/src/routes/changelog/(entries)/2026-06-29.markdoc @@ -0,0 +1,28 @@ +--- +layout: changelog +title: Announcing Appwrite 1.9.5 for self-hosted deployments +date: 2026-06-29 +cover: /images/blog/appwrite-1-9-5-self-hosted-release/cover.avif +--- + +After multiple updates and fixes, Appwrite 1.9.5 is now available for self-hosting. + +Most notably, this release includes: + +- Presences API for online, typing, and activity states +- BigInt columns for Databases +- Rust runtime for Functions +- X (formerly Twitter) OAuth support for Auth +- Email policies to block disposable, aliased, and free email addresses +- Bun and Deno build runtimes for Sites +- Git deployment triggers for Functions and Sites +- Parallel chunk uploads for faster Storage uploads +- Broader migration coverage for project settings, keys, and integrations + +Head over to our [migration guide](https://appwrite.io/docs/advanced/self-hosting/production/updates) to learn how you can upgrade your Appwrite instance. Please run the [migrate command](https://appwrite.io/docs/advanced/self-hosting/production/updates#running-the-migration) even if upgrading from 1.9.0. + +For the complete list of updates and fixes, check out the [release notes](https://github.com/appwrite/appwrite/releases/tag/1.9.5) on GitHub. + +{% arrow_link href="/docs/advanced/self-hosting/production/updates" %} +Upgrade your self-hosted instance +{% /arrow_link %} diff --git a/src/routes/docs/advanced/self-hosting/configuration/databases/+page.markdoc b/src/routes/docs/advanced/self-hosting/configuration/databases/+page.markdoc index 0b727908090..0ed79387d0a 100644 --- a/src/routes/docs/advanced/self-hosting/configuration/databases/+page.markdoc +++ b/src/routes/docs/advanced/self-hosting/configuration/databases/+page.markdoc @@ -23,7 +23,7 @@ docker run -it --rm \ --volume /var/run/docker.sock:/var/run/docker.sock \ --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ --entrypoint="install" \ - appwrite/appwrite:1.9.0 \ + appwrite/appwrite:1.9.5 \ --database=mongodb ``` {% /tabsitem %} @@ -34,7 +34,7 @@ docker run -it --rm ^ --volume //var/run/docker.sock:/var/run/docker.sock ^ --volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^ --entrypoint="install" ^ - appwrite/appwrite:1.9.0 ^ + appwrite/appwrite:1.9.5 ^ --database=mongodb ``` {% /tabsitem %} @@ -45,7 +45,7 @@ docker run -it --rm ` --volume /var/run/docker.sock:/var/run/docker.sock ` --volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ` --entrypoint="install" ` - appwrite/appwrite:1.9.0 ` + appwrite/appwrite:1.9.5 ` --database=mongodb ``` {% /tabsitem %} diff --git a/src/routes/docs/advanced/self-hosting/installation/+page.markdoc b/src/routes/docs/advanced/self-hosting/installation/+page.markdoc index 0d2ea67dfa7..c3327f8c4ba 100644 --- a/src/routes/docs/advanced/self-hosting/installation/+page.markdoc +++ b/src/routes/docs/advanced/self-hosting/installation/+page.markdoc @@ -38,7 +38,7 @@ docker run -it --rm \ --volume /var/run/docker.sock:/var/run/docker.sock \ --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ --entrypoint="install" \ - appwrite/appwrite:1.9.0 + appwrite/appwrite:1.9.5 ``` {% /tabsitem %} @@ -49,7 +49,7 @@ docker run -it --rm ^ --volume //var/run/docker.sock:/var/run/docker.sock ^ --volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^ --entrypoint="install" ^ - appwrite/appwrite:1.9.0 + appwrite/appwrite:1.9.5 ``` {% /tabsitem %} @@ -60,7 +60,7 @@ docker run -it --rm ` --volume /var/run/docker.sock:/var/run/docker.sock ` --volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ` --entrypoint="install" ` - appwrite/appwrite:1.9.0 + appwrite/appwrite:1.9.5 ``` {% /tabsitem %} {% /tabs %} @@ -156,7 +156,7 @@ On non-Linux hosts, the server might take a few minutes to start after installat ## SDK version compatibility {% #sdk-version-compatibility %} -The tables below map each released self-hosted Appwrite version to the SDK versions that were current at the time of that release. Use this to pin your SDK to a version known to work with your server. The latest stable self-hosted Appwrite release is 1.9.0. +The tables below map each released self-hosted Appwrite version to the SDK versions that were current at the time of that release. Use this to pin your SDK to a version known to work with your server. The latest stable self-hosted Appwrite release is 1.9.5. ### Client SDKs {% #client-compatibility %} @@ -216,6 +216,13 @@ The tables below map each released self-hosted Appwrite version to the SDK versi * 0.27.1 * 16.0.0 * 14.1.0 +--- +* 1.9.5 +* 26.1.0 +* 25.2.0 +* 0.33.0 +* 18.2.0 +* 25.2.0 {% /table %} ### Server SDKs {% #server-compatibility %} @@ -316,6 +323,18 @@ The tables below map each released self-hosted Appwrite version to the SDK versi * 16.0.0 * 15.0.0 * 17.4.0 +--- +* 1.9.5 +* 26.2.0 +* 21.0.0 +* 26.1.0 +* 25.1.0 +* 25.1.0 +* 5.1.0 +* v5.1.0 +* 19.1.0 +* 18.1.0 +* 22.3.0 {% /table %} # Managing your installation {% #managing-installation %} diff --git a/static/images/blog/appwrite-1-9-5-self-hosted-release/cover.avif b/static/images/blog/appwrite-1-9-5-self-hosted-release/cover.avif new file mode 100644 index 0000000000000000000000000000000000000000..47412df1bf7d763f2c90555d94e167c255c331e5 GIT binary patch literal 12700 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 L$NeAnzfJ!G8v$a$ literal 0 HcmV?d00001 From c1b5617fb0fc85fd97134edba3ec7e72d3e03d05 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Mon, 29 Jun 2026 11:14:40 +0530 Subject: [PATCH 38/61] Address review feedback on 1.9.5 release post - Expand blog FAQs to cover all updates and add a self-hosting FAQ - Add a fresh self-host section and show the install/upgrade/migrate commands inline - Fix changelog migration wording --- .../+page.markdoc | 47 ++++++++++++++++--- .../changelog/(entries)/2026-06-29.markdoc | 2 +- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc b/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc index 44eb39e6024..38fbd104bcb 100644 --- a/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc +++ b/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc @@ -12,14 +12,22 @@ callToAction: true faqs: - question: "What is new in Appwrite 1.9.5 for self-hosted deployments?" answer: "Appwrite 1.9.5 brings the Presences API, BigInt columns for [Databases](/docs/products/databases), the Rust runtime for [Functions](/docs/products/functions), X OAuth and email policies for [Auth](/docs/products/auth), Bun and Deno build runtimes and Git deployment triggers for [Sites](/docs/products/sites), faster Storage uploads with parallel chunks, and broader migration coverage." + - question: "How do I self-host Appwrite 1.9.5?" + answer: "Run the Docker installer with the 1.9.5 image, then open the setup wizard on port 20080 to finish configuration. See the [self-hosting installation guide](/docs/advanced/self-hosting/installation) for the full command and system requirements." + - question: "How do I upgrade my self-hosted instance to 1.9.5?" + answer: "Back up your data, pull the 1.9.5 image, run the upgrade command, and run the migration. Always test the upgrade on a staging environment first." - question: "What is the Presences API used for?" answer: "The Presences API tracks short-lived user states such as online, away, typing, editing, or viewing. You can use it to build online indicators, typing states, collaborative editors, multiplayer features, and live activity feeds without managing presence channels yourself." - question: "What are BigInt columns in Appwrite?" answer: "BigInt columns store 64-bit signed integers in [Databases](/docs/products/databases). They are suited to large counters, external IDs, high-resolution timestamps, and financial values that need integer precision without floating-point rounding." + - question: "Does Appwrite Functions support Rust?" + answer: "Yes. Appwrite 1.9.5 adds Rust as a first-class [Functions](/docs/products/functions) runtime, so you can write and deploy functions in Rust and pair them with the official Appwrite Rust SDK." + - question: "Can I build my Appwrite Sites with Bun or Deno?" + answer: "Yes. Appwrite [Sites](/docs/products/sites) can now build Node-based frameworks with Bun or Deno. You can switch the build runtime per Site from its Runtime settings, and the change applies on the next deployment." - question: "Can I block disposable or free email addresses at signup?" answer: "Yes. Email policies in [Appwrite Auth](/docs/products/auth) let you block disposable inboxes, aliased addresses, and free email providers at user creation and on email updates, either from the Console or through any server SDK." - - question: "How do I upgrade my self-hosted instance to 1.9.5?" - answer: "Back up your data, pull the 1.9.5 image, run the upgrade command, and run the migration. Always test the upgrade on a staging environment first." + - question: "How much faster are Storage uploads in 1.9.5?" + answer: "Appwrite SDKs now upload Storage file chunks in parallel. In our Node SDK benchmark, a 1.28 GB upload dropped from 4 minutes 44 seconds to under 40 seconds, a 7.10x improvement, with no API changes required." --- **Appwrite 1.9.5** is now available for self-hosted deployments. @@ -96,12 +104,39 @@ Read the announcement Migrations in 1.9.5 carry over far more than your data. Project configuration now transfers alongside it, including API keys, project variables, webhooks, OAuth providers, SMTP settings, email templates, custom domains, and security policies. Moving a project between Appwrite instances, such as from Appwrite Cloud to a self-hosted instance, now reproduces its setup instead of just its records. +# Self-host Appwrite 1.9.5 + +If you are setting up Appwrite for the first time, all you need is Docker installed. Run the installer with the 1.9.5 image, then open `http://localhost:20080` to complete the setup wizard. + +```bash +docker run -it --rm \ + --publish 20080:20080 \ + --volume /var/run/docker.sock:/var/run/docker.sock \ + --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ + --entrypoint="install" \ + appwrite/appwrite:1.9.5 +``` + +For system requirements and the full walkthrough, see the [installation guide](/docs/advanced/self-hosting/installation). + # Upgrade your self-hosted instance -As with every Appwrite upgrade: +If you are already running Appwrite, back up your data first, then run the upgrade command: + +```bash +docker run -it --rm \ + --publish 20080:20080 \ + --volume /var/run/docker.sock:/var/run/docker.sock \ + --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ + --entrypoint="upgrade" \ + appwrite/appwrite:1.9.5 +``` + +After the upgrade is complete, run the migration: -- Back up your data before upgrading -- [Install or upgrade your self-hosted instance](/docs/advanced/self-hosting/production/updates#install-next-version) to **Appwrite 1.9.5** -- [Run the migration](/docs/advanced/self-hosting/production/updates#running-the-migration), even if you are upgrading from 1.9.0 +```sh +cd appwrite/ +docker compose exec appwrite migrate +``` To view the complete list of changes, fixes, and contributions, check out the full [release notes](https://github.com/appwrite/appwrite/releases/tag/1.9.5). diff --git a/src/routes/changelog/(entries)/2026-06-29.markdoc b/src/routes/changelog/(entries)/2026-06-29.markdoc index 5973d23cb70..874e1aea268 100644 --- a/src/routes/changelog/(entries)/2026-06-29.markdoc +++ b/src/routes/changelog/(entries)/2026-06-29.markdoc @@ -19,7 +19,7 @@ Most notably, this release includes: - Parallel chunk uploads for faster Storage uploads - Broader migration coverage for project settings, keys, and integrations -Head over to our [migration guide](https://appwrite.io/docs/advanced/self-hosting/production/updates) to learn how you can upgrade your Appwrite instance. Please run the [migrate command](https://appwrite.io/docs/advanced/self-hosting/production/updates#running-the-migration) even if upgrading from 1.9.0. +Head over to our [migration guide](https://appwrite.io/docs/advanced/self-hosting/production/updates) to learn how you can upgrade your Appwrite instance. Please run the [migrate command](https://appwrite.io/docs/advanced/self-hosting/production/updates#running-the-migration) even if you are upgrading from 1.9.0. For the complete list of updates and fixes, check out the [release notes](https://github.com/appwrite/appwrite/releases/tag/1.9.5) on GitHub. From c7fe0d56b85d912fae471e33f9c0766ec3091659 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Mon, 29 Jun 2026 11:41:50 +0530 Subject: [PATCH 39/61] Add worker-screenshots and task-interval services to compose generator Match the 1.9.x base compose service set (Postgres/embedding excluded). --- .../compose-generator/composeData.ts | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/lib/components/compose-generator/composeData.ts b/src/lib/components/compose-generator/composeData.ts index 2334d50881b..7f54af998be 100644 --- a/src/lib/components/compose-generator/composeData.ts +++ b/src/lib/components/compose-generator/composeData.ts @@ -582,6 +582,61 @@ services: - _APP_STORAGE_WASABI_BUCKET - _APP_DOMAIN_SITES + appwrite-worker-screenshots: + image: appwrite/appwrite:1.9.5 + entrypoint: worker-screenshots + <<: *x-logging + container_name: appwrite-worker-screenshots + restart: unless-stopped + networks: + - appwrite + volumes: + - appwrite-uploads:/storage/uploads:rw + depends_on: + redis: + condition: service_healthy + __DB_SERVICE__: + condition: service_healthy + environment: + - _APP_ENV + - _APP_WORKER_PER_CORE + - _APP_OPENSSL_KEY_V1 + - _APP_BROWSER_HOST + - _APP_OPTIONS_FORCE_HTTPS + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS + - _APP_DB_ADAPTER + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + - _APP_LOGGING_CONFIG + - _APP_STORAGE_DEVICE + - _APP_STORAGE_S3_ACCESS_KEY + - _APP_STORAGE_S3_SECRET + - _APP_STORAGE_S3_REGION + - _APP_STORAGE_S3_BUCKET + - _APP_STORAGE_S3_ENDPOINT + - _APP_STORAGE_DO_SPACES_ACCESS_KEY + - _APP_STORAGE_DO_SPACES_SECRET + - _APP_STORAGE_DO_SPACES_REGION + - _APP_STORAGE_DO_SPACES_BUCKET + - _APP_STORAGE_BACKBLAZE_ACCESS_KEY + - _APP_STORAGE_BACKBLAZE_SECRET + - _APP_STORAGE_BACKBLAZE_REGION + - _APP_STORAGE_BACKBLAZE_BUCKET + - _APP_STORAGE_LINODE_ACCESS_KEY + - _APP_STORAGE_LINODE_SECRET + - _APP_STORAGE_LINODE_REGION + - _APP_STORAGE_LINODE_BUCKET + - _APP_STORAGE_WASABI_ACCESS_KEY + - _APP_STORAGE_WASABI_SECRET + - _APP_STORAGE_WASABI_REGION + - _APP_STORAGE_WASABI_BUCKET + appwrite-worker-certificates: image: appwrite/appwrite:1.9.5 entrypoint: worker-certificates @@ -867,6 +922,43 @@ services: - _APP_MAINTENANCE_RETENTION_USAGE_HOURLY - _APP_MAINTENANCE_RETENTION_SCHEDULES + appwrite-task-interval: + image: appwrite/appwrite:1.9.5 + entrypoint: interval + <<: *x-logging + container_name: appwrite-task-interval + restart: unless-stopped + networks: + - appwrite + depends_on: + __DB_SERVICE__: + condition: service_healthy + redis: + condition: service_healthy + environment: + - _APP_ENV + - _APP_WORKER_PER_CORE + - _APP_OPENSSL_KEY_V1 + - _APP_DOMAIN + - _APP_DOMAIN_TARGET_CNAME + - _APP_DOMAIN_TARGET_AAAA + - _APP_DOMAIN_TARGET_A + - _APP_DOMAIN_TARGET_CAA + - _APP_DNS + - _APP_DOMAIN_FUNCTIONS + - _APP_DOMAIN_SITES + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS + - _APP_DB_ADAPTER + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + - _APP_LOGGING_CONFIG + appwrite-task-stats-resources: image: appwrite/appwrite:1.9.5 container_name: appwrite-task-stats-resources From 423dfe5dcad05c86ada8fcd37757d7daf3afaf9f Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Mon, 29 Jun 2026 15:37:03 +0530 Subject: [PATCH 40/61] Add changelog entry for paused free project deletion --- src/routes/changelog/(entries)/2026-06-29.markdoc | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/routes/changelog/(entries)/2026-06-29.markdoc diff --git a/src/routes/changelog/(entries)/2026-06-29.markdoc b/src/routes/changelog/(entries)/2026-06-29.markdoc new file mode 100644 index 00000000000..23e0bd1b3c5 --- /dev/null +++ b/src/routes/changelog/(entries)/2026-06-29.markdoc @@ -0,0 +1,9 @@ +--- +layout: changelog +title: 'Paused free projects are deleted after 90 days' +date: 2026-06-29 +--- + +Free projects are paused after one week of inactivity. A free project that stays paused for 90 days will now be deleted, including all of its resources. + +This only applies to projects on free-tier organizations. To keep a paused project, open it in the Appwrite Console to resume it, or upgrade its organization to a paid plan before the 90-day window ends. From 7aecc62f8020eafdc5b30e18e62e2d6d68b6041a Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Mon, 29 Jun 2026 13:28:43 +0200 Subject: [PATCH 41/61] Revert "Revert "ci: move production deploy to declarative setup, " --- .github/workflows/production.yml | 78 ++++++++++++++------------------ .github/workflows/staging.yml | 19 ++++---- 2 files changed, 46 insertions(+), 51 deletions(-) diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 2a3b7b22780..07a6a2af535 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -6,27 +6,28 @@ on: workflow_dispatch: env: + ENVIRONMENT: production + PROJECT: website + DECLARATIVE_OWNER: appwrite-labs + DECLARATIVE_REPOSITORY: assets-applications TAG: ${{ github.event.release.tag_name || github.sha }} - STACK_FILE: docker/production.yml - REPOSITORY: website - REGISTRY_USERNAME: christyjacob4 jobs: build: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v6 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . push: true @@ -49,49 +50,40 @@ jobs: "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" "SENTRY_RELEASE=${{ github.event.release.tag_name }}" - deploy_kubernetes: + deploy: if: github.event_name != 'release' || !contains(github.event.release.tag_name, '-rc') - strategy: - matrix: - region: [{ full: fra1, short: fra }] needs: build runs-on: ubuntu-latest + concurrency: + group: declarative-deploy-website + cancel-in-progress: false steps: - - name: Checkout the repo - uses: actions/checkout@v4 - - name: Install Kubectl - uses: azure/setup-kubectl@v4 - - name: Install Helm - uses: azure/setup-helm@v4 - - name: Install doctl - uses: digitalocean/action-doctl@v2 + - name: Get token for ${{ env.DECLARATIVE_REPOSITORY }} + id: app-token + uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 with: - token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} - - name: Save DigitalOcean kubeconfig with short-lived credentials - run: doctl kubernetes cluster kubeconfig save --expiry-seconds 600 assets-${{ matrix.region.full }}-prod - - - name: Ensure namespaces exist - run: | - kubectl create namespace website --dry-run=client -o yaml | kubectl apply -f - + app-id: ${{ vars.DECLARATIVE_DEPLOYMENT_GITHUB_APP_ID }} + private-key: ${{ secrets.DECLARATIVE_DEPLOYMENT_GITHUB_APP_PRIVATE_KEY }} + owner: ${{ env.DECLARATIVE_OWNER }} + repositories: ${{ env.DECLARATIVE_REPOSITORY }} - - name: Create docker pull secret - run: | - kubectl -n website create secret docker-registry ghcr \ - --docker-server=ghcr.io \ - --docker-username=${{ secrets.GHCR_USERNAME }} \ - --docker-password=${{ secrets.GHCR_TOKEN }} \ - --docker-email=ci@appwrite.io \ - --dry-run=client -o yaml | kubectl apply -f - + - name: Checkout ${{ env.DECLARATIVE_REPOSITORY }} + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + repository: ${{ env.DECLARATIVE_OWNER }}/${{ env.DECLARATIVE_REPOSITORY }} + token: ${{ steps.app-token.outputs.token }} - - name: Create app secrets - run: | - kubectl -n website create secret generic website-secrets \ - --from-literal=STATSIG_SERVER_SECRET='${{ secrets.STATSIG_SERVER_SECRET }}' \ - --dry-run=client -o yaml | kubectl apply -f - + - name: Update image tag + run: yq -i '.website.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml - - name: Deploy + - name: Commit and push run: | - helm upgrade --install --namespace website website deploy/website/ \ - --values deploy/website/environments/production/${{ matrix.region.full }}.values.yaml \ - --set imagePullSecret='ghcr' \ - --set version=${{ env.TAG }} + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml + if git diff --cached --quiet; then + echo "No changes to commit" + else + git commit -m "chore(${{ env.ENVIRONMENT }}): ${{ env.PROJECT }} image tag to ${{ env.TAG }}" + git push + fi diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index a581c48fbf5..3736ba9d148 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -25,24 +25,24 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Login to GitHub Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ${{ env.REGISTRY_GITHUB }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ${{ env.REGISTRY_DOCKERHUB }} username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v6 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . push: true @@ -69,10 +69,13 @@ jobs: deploy: needs: build runs-on: ubuntu-latest + concurrency: + group: declarative-deploy-website + cancel-in-progress: false steps: - name: Get token for ${{ env.DECLARATIVE_REPOSITORY }} id: app-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 with: app-id: ${{ vars.DECLARATIVE_DEPLOYMENT_GITHUB_APP_ID }} private-key: ${{ secrets.DECLARATIVE_DEPLOYMENT_GITHUB_APP_PRIVATE_KEY }} @@ -80,19 +83,19 @@ jobs: repositories: ${{ env.DECLARATIVE_REPOSITORY }} - name: Checkout ${{ env.DECLARATIVE_REPOSITORY }} - uses: actions/checkout@v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: repository: ${{ env.DECLARATIVE_OWNER }}/${{ env.DECLARATIVE_REPOSITORY }} token: ${{ steps.app-token.outputs.token }} - name: Update image tag - run: yq -i '.website.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/fra1.yaml + run: yq -i '.website.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml - name: Commit and push run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/fra1.yaml + git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml if git diff --cached --quiet; then echo "No changes to commit" else From 16c4232ae1e5d387ebdafdaf8751ce151c057cf1 Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:27:04 +0200 Subject: [PATCH 42/61] ci: push production image to DockerHub alongside GHCR The production workflow's "Login to DockerHub" step actually targeted ghcr.io, so production images were only ever pushed to GHCR. Add a real Docker Hub login and emit both registry tags, matching staging. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/production.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 07a6a2af535..f36eda653bf 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -10,6 +10,9 @@ env: PROJECT: website DECLARATIVE_OWNER: appwrite-labs DECLARATIVE_REPOSITORY: assets-applications + REGISTRY_GITHUB: ghcr.io + REGISTRY_DOCKERHUB: docker.io + IMAGE_NAME: appwrite/website TAG: ${{ github.event.release.tag_name || github.sha }} jobs: @@ -19,19 +22,28 @@ jobs: - name: Checkout the repo uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - - name: Login to DockerHub + - name: Login to GitHub Container Registry uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: - registry: ghcr.io + registry: ${{ env.REGISTRY_GITHUB }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to Docker Hub + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + with: + registry: ${{ env.REGISTRY_DOCKERHUB }} + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and push uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . push: true - tags: ghcr.io/appwrite/website:${{ env.TAG }} + tags: | + ${{ env.REGISTRY_GITHUB }}/${{ env.IMAGE_NAME }}:${{ env.TAG }} + ${{ env.REGISTRY_DOCKERHUB }}/${{ env.IMAGE_NAME }}:${{ env.TAG }} build-args: | "PUBLIC_APPWRITE_ENDPOINT=${{ vars.PUBLIC_APPWRITE_ENDPOINT }}" "PUBLIC_APPWRITE_DASHBOARD=${{ vars.PUBLIC_APPWRITE_DASHBOARD }}" From 376e4177be384af7c10b0c45e680ae3632afcec7 Mon Sep 17 00:00:00 2001 From: adityaoberai Date: Mon, 29 Jun 2026 18:35:02 +0530 Subject: [PATCH 43/61] Convert journeys to guides in docs --- CONTENT.md | 2 +- STYLE.md | 6 +++--- src/routes/docs/advanced/security/mfa/+page.markdoc | 2 +- src/routes/docs/products/auth/+layout.svelte | 2 +- src/routes/docs/products/databases/+layout.svelte | 2 +- src/routes/docs/products/functions/+layout.svelte | 2 +- src/routes/docs/products/messaging/+layout.svelte | 2 +- src/routes/docs/products/messaging/fcm/+page.markdoc | 2 +- src/routes/docs/products/messaging/mailgun/+page.markdoc | 2 +- src/routes/docs/products/messaging/msg91/+page.markdoc | 2 +- src/routes/docs/products/messaging/sendgrid/+page.markdoc | 2 +- src/routes/docs/products/messaging/smtp/+page.markdoc | 2 +- src/routes/docs/products/messaging/targets/+page.markdoc | 2 +- src/routes/docs/products/messaging/telesign/+page.markdoc | 2 +- src/routes/docs/products/messaging/textmagic/+page.markdoc | 2 +- src/routes/docs/products/messaging/vonage/+page.markdoc | 2 +- src/routes/docs/products/sites/+layout.svelte | 2 +- src/routes/docs/products/storage/+layout.svelte | 2 +- src/routes/docs/tooling/ai/+layout.svelte | 2 +- src/routes/docs/tooling/ai/+page.markdoc | 2 +- src/routes/integrations/push-fcm/+page.markdoc | 2 +- 21 files changed, 23 insertions(+), 23 deletions(-) diff --git a/CONTENT.md b/CONTENT.md index 0886ecd9dfb..91519c1361f 100644 --- a/CONTENT.md +++ b/CONTENT.md @@ -193,7 +193,7 @@ Remember to use a specific language label if the code is using an Appwrite SDK. ### Sections -Use sections when there is a clear step-by-step format to a page. This is used mainly in journey pages and tutorials. +Use sections when there is a clear step-by-step format to a page. This is used mainly in guide pages and tutorials. ```md {% section #featured-products-1 step=1 title="Title" %} diff --git a/STYLE.md b/STYLE.md index 5571caa22ea..f5931914fd6 100644 --- a/STYLE.md +++ b/STYLE.md @@ -94,7 +94,7 @@ Each product page has three main sections - These pages usually align with sections shown in the product in the Appwrite Console. - Focused on describing concepts a user should know, but not actions you might take. - Cover all the details -- Journeys +- Guides - These pages focus on common actions and work flows - Detailed examples that span many concepts - Like cookbook at other organizations' documentation. @@ -222,7 +222,7 @@ Split content such that each piece makes sense without reading dependents or exp - [ ] Update response code [src/routes/docs/apis/response-codes/+page.markdoc](src/routes/docs/apis/response-codes/+page.markdoc) - [ ] Bump latest SDK versions in SDKs page, quick start, and tutorials - [ ] Create new sections for new products -- [ ] Create new concept and journey pages for new features +- [ ] Create new concept and guide pages for new features - [ ] Update docs for breaking changes ### Documenting a new API @@ -351,7 +351,7 @@ easily, and the code example is expected to be runnable and complete. This means, you need to include imports, dependencies, and all parts needed to arrive at a functional example. -For concept and journey product pages, still try your best to have complete examples, unless: +For concept and guide product pages, still try your best to have complete examples, unless: 1. The example will become opinionated. We avoid opinionated implementation and choices in product pages. Keep them in blogs, quick starts, and tutorials. 2. The example cannot be given in a complete form cleanly. For example, many of the Messaging services's examples cannot be given in complete form because the boiler plate and set up is complex and documented in Android/Swift documentation. diff --git a/src/routes/docs/advanced/security/mfa/+page.markdoc b/src/routes/docs/advanced/security/mfa/+page.markdoc index bda35532ff8..d9c4d450fc3 100644 --- a/src/routes/docs/advanced/security/mfa/+page.markdoc +++ b/src/routes/docs/advanced/security/mfa/+page.markdoc @@ -10,7 +10,7 @@ More factors of authentication will be added in the future. {% info title="Looking to add MFA to your app?" %} This page covers MFA for your Appwrite Console account. -If you're looking to add MFA to your app, follow the [Multi-factor authentication journey](/docs/products/auth/mfa). +If you're looking to add MFA to your app, follow the [Multi-factor authentication guide](/docs/products/auth/mfa). {% /info %} # Enable MFA {% #enable-mfa %} diff --git a/src/routes/docs/products/auth/+layout.svelte b/src/routes/docs/products/auth/+layout.svelte index 850ee6aca28..e651ad26125 100644 --- a/src/routes/docs/products/auth/+layout.svelte +++ b/src/routes/docs/products/auth/+layout.svelte @@ -79,7 +79,7 @@ ] }, { - label: 'Journeys', + label: 'Guides', items: [ { label: 'Email and password login', diff --git a/src/routes/docs/products/databases/+layout.svelte b/src/routes/docs/products/databases/+layout.svelte index 87f1ffb5a32..6c1f5158d47 100644 --- a/src/routes/docs/products/databases/+layout.svelte +++ b/src/routes/docs/products/databases/+layout.svelte @@ -76,7 +76,7 @@ ] }, { - label: 'Journeys', + label: 'Guides', items: [ { label: 'Pagination', diff --git a/src/routes/docs/products/functions/+layout.svelte b/src/routes/docs/products/functions/+layout.svelte index a6ae8dfceeb..738aa5db765 100644 --- a/src/routes/docs/products/functions/+layout.svelte +++ b/src/routes/docs/products/functions/+layout.svelte @@ -51,7 +51,7 @@ ] }, { - label: 'Journeys', + label: 'Guides', items: [ { label: 'Templates', diff --git a/src/routes/docs/products/messaging/+layout.svelte b/src/routes/docs/products/messaging/+layout.svelte index 224bbb4a65c..ed4257acc7d 100644 --- a/src/routes/docs/products/messaging/+layout.svelte +++ b/src/routes/docs/products/messaging/+layout.svelte @@ -84,7 +84,7 @@ ] }, { - label: 'Journeys', + label: 'Guides', items: [ { label: 'Send push notifications', diff --git a/src/routes/docs/products/messaging/fcm/+page.markdoc b/src/routes/docs/products/messaging/fcm/+page.markdoc index b674fcdbb16..d769eeee1fe 100644 --- a/src/routes/docs/products/messaging/fcm/+page.markdoc +++ b/src/routes/docs/products/messaging/fcm/+page.markdoc @@ -57,7 +57,7 @@ Some additional configuration is required to enable push notifications in your m 1. Add `google-services.json` at the root of your project. 1. Add Google Services class path to your app-level Gradle dependencies block `"com.google.gms:google-services:4.4.0"`. 1. Add Google Services plugin to your app-level Gradle in the plugins block as `"com.google.gms.google-services"`. -1. Add notification handler service to `AndroidManifest.xml` inside the application tag, alongside other activities. Find an example of this service in the [Send push notification](/docs/products/messaging/send-push-notifications#add-targets) journey. +1. Add notification handler service to `AndroidManifest.xml` inside the application tag, alongside other activities. Find an example of this service in the [Send push notification](/docs/products/messaging/send-push-notifications#add-targets) guide. ```xml diff --git a/src/routes/docs/products/messaging/mailgun/+page.markdoc b/src/routes/docs/products/messaging/mailgun/+page.markdoc index 2b63a570aed..597b5e91867 100644 --- a/src/routes/docs/products/messaging/mailgun/+page.markdoc +++ b/src/routes/docs/products/messaging/mailgun/+page.markdoc @@ -319,7 +319,7 @@ async fn main() -> Result<(), Box> { {% /tabsitem %} {% /tabs %} -You can follow the [Send email messages](/docs/products/messaging/send-push-notifications) journey to send your first push notification and test your provider. +You can follow the [Send email messages](/docs/products/messaging/send-push-notifications) guide to send your first push notification and test your provider. {% /section %} {% section #manage-provider step=4 title="Manage provider" %} diff --git a/src/routes/docs/products/messaging/msg91/+page.markdoc b/src/routes/docs/products/messaging/msg91/+page.markdoc index 0ea24698aec..62e4cd076ab 100644 --- a/src/routes/docs/products/messaging/msg91/+page.markdoc +++ b/src/routes/docs/products/messaging/msg91/+page.markdoc @@ -353,7 +353,7 @@ async fn main() -> Result<(), Box> { {% /tabsitem %} {% /tabs %} -You can follow the [Send email messages](/docs/products/messaging/send-sms-messages) journey to send your first push notification and test your provider. +You can follow the [Send email messages](/docs/products/messaging/send-sms-messages) guide to send your first push notification and test your provider. {% /section %} diff --git a/src/routes/docs/products/messaging/sendgrid/+page.markdoc b/src/routes/docs/products/messaging/sendgrid/+page.markdoc index 37ade828b70..0ce661d1afb 100644 --- a/src/routes/docs/products/messaging/sendgrid/+page.markdoc +++ b/src/routes/docs/products/messaging/sendgrid/+page.markdoc @@ -312,7 +312,7 @@ async fn main() -> Result<(), Box> { {% /tabsitem %} {% /tabs %} -You can follow the [Send email messages](/docs/products/messaging/send-email-messages) journey to send your first push notification and test your provider. +You can follow the [Send email messages](/docs/products/messaging/send-email-messages) guide to send your first push notification and test your provider. {% /section %} {% section #manage-provider step=4 title="Manage provider" %} diff --git a/src/routes/docs/products/messaging/smtp/+page.markdoc b/src/routes/docs/products/messaging/smtp/+page.markdoc index 52e7fd580ab..055fdad50b9 100644 --- a/src/routes/docs/products/messaging/smtp/+page.markdoc +++ b/src/routes/docs/products/messaging/smtp/+page.markdoc @@ -321,7 +321,7 @@ async fn main() -> Result<(), Box> { {% /tabsitem %} {% /tabs %} -You can follow the [Send email messages](/docs/products/messaging/send-push-notifications) journey to send your first push notification and test your provider. +You can follow the [Send email messages](/docs/products/messaging/send-push-notifications) guide to send your first push notification and test your provider. {% /section %} {% section #manage-provider step=4 title="Manage provider" %} diff --git a/src/routes/docs/products/messaging/targets/+page.markdoc b/src/routes/docs/products/messaging/targets/+page.markdoc index 26c8bf9d1fa..2b6a9344c64 100644 --- a/src/routes/docs/products/messaging/targets/+page.markdoc +++ b/src/routes/docs/products/messaging/targets/+page.markdoc @@ -71,7 +71,7 @@ Push notifications require configuration on both the Appwrite platform and your 1. Add `google-services.json` at the root of your project. 1. Add Google Services class path to your app-level Gradle dependencies block `"com.google.gms:google-services:4.4.0"`. 1. Add Google Services plugin to your app-level Gradle in the plugins block as `"com.google.gms.google-services"`. -1. Add notification handler service to `AndroidManifest.xml` inside the application tag, alongside other activities. Find an example of this service in the [Send push notification](/docs/products/messaging/send-push-notifications#add-targets) journey. +1. Add notification handler service to `AndroidManifest.xml` inside the application tag, alongside other activities. Find an example of this service in the [Send push notification](/docs/products/messaging/send-push-notifications#add-targets) guide. ```xml diff --git a/src/routes/docs/products/messaging/telesign/+page.markdoc b/src/routes/docs/products/messaging/telesign/+page.markdoc index 3b8292fd328..db63679d533 100644 --- a/src/routes/docs/products/messaging/telesign/+page.markdoc +++ b/src/routes/docs/products/messaging/telesign/+page.markdoc @@ -352,7 +352,7 @@ async fn main() -> Result<(), Box> { {% /tabsitem %} {% /tabs %} -You can follow the [Send SMS messages](/docs/products/messaging/send-sms-messages) journey to send your first push notification and test your provider. +You can follow the [Send SMS messages](/docs/products/messaging/send-sms-messages) guide to send your first push notification and test your provider. {% /section %} {% section #manage-provider step=4 title="Manage provider" %} diff --git a/src/routes/docs/products/messaging/textmagic/+page.markdoc b/src/routes/docs/products/messaging/textmagic/+page.markdoc index 76d09c143e0..bd9e5869ddf 100644 --- a/src/routes/docs/products/messaging/textmagic/+page.markdoc +++ b/src/routes/docs/products/messaging/textmagic/+page.markdoc @@ -352,7 +352,7 @@ async fn main() -> Result<(), Box> { {% /tabsitem %} {% /tabs %} -You can follow the [Send SMS messages](/docs/products/messaging/send-sms-messages) journey to send your first push notification and test your provider. +You can follow the [Send SMS messages](/docs/products/messaging/send-sms-messages) guide to send your first push notification and test your provider. {% /section %} {% section #manage-provider step=4 title="Manage provider" %} diff --git a/src/routes/docs/products/messaging/vonage/+page.markdoc b/src/routes/docs/products/messaging/vonage/+page.markdoc index 0d57869a326..e3ff2728dfe 100644 --- a/src/routes/docs/products/messaging/vonage/+page.markdoc +++ b/src/routes/docs/products/messaging/vonage/+page.markdoc @@ -354,7 +354,7 @@ async fn main() -> Result<(), Box> { {% /tabsitem %} {% /tabs %} -You can follow the [Send SMS messages](/docs/products/messaging/send-sms-messages) journey to send your first push notification and test your provider. +You can follow the [Send SMS messages](/docs/products/messaging/send-sms-messages) guide to send your first push notification and test your provider. {% /section %} {% section #manage-provider step=4 title="Manage provider" %} diff --git a/src/routes/docs/products/sites/+layout.svelte b/src/routes/docs/products/sites/+layout.svelte index 36454587f7d..62c76a92ce8 100644 --- a/src/routes/docs/products/sites/+layout.svelte +++ b/src/routes/docs/products/sites/+layout.svelte @@ -59,7 +59,7 @@ ] }, { - label: 'Journeys', + label: 'Guides', items: [ { label: 'Templates', diff --git a/src/routes/docs/products/storage/+layout.svelte b/src/routes/docs/products/storage/+layout.svelte index 358647ae855..122404835c6 100644 --- a/src/routes/docs/products/storage/+layout.svelte +++ b/src/routes/docs/products/storage/+layout.svelte @@ -39,7 +39,7 @@ ] }, { - label: 'Journeys', + label: 'Guides', items: [ { label: 'Upload and download', diff --git a/src/routes/docs/tooling/ai/+layout.svelte b/src/routes/docs/tooling/ai/+layout.svelte index 163e7c56a25..69f0b369f76 100644 --- a/src/routes/docs/tooling/ai/+layout.svelte +++ b/src/routes/docs/tooling/ai/+layout.svelte @@ -105,7 +105,7 @@ ] }, { - label: 'Journeys', + label: 'Guides', items: [ { label: 'AI in Functions', diff --git a/src/routes/docs/tooling/ai/+page.markdoc b/src/routes/docs/tooling/ai/+page.markdoc index 4662f596bb3..97d9884c66b 100644 --- a/src/routes/docs/tooling/ai/+page.markdoc +++ b/src/routes/docs/tooling/ai/+page.markdoc @@ -135,7 +135,7 @@ Open-source benchmark evaluating how well AI models understand Appwrite's APIs a {% /cards_item %} {% /cards %} -# Journeys {% #journeys %} +# Guides {% #guides %} Guides for building AI-powered features on top of Appwrite, from running models in Functions to building full agent pipelines. diff --git a/src/routes/integrations/push-fcm/+page.markdoc b/src/routes/integrations/push-fcm/+page.markdoc index 650ef32154a..c1c6bf3a7a6 100644 --- a/src/routes/integrations/push-fcm/+page.markdoc +++ b/src/routes/integrations/push-fcm/+page.markdoc @@ -59,7 +59,7 @@ To test the provider on mobile apps, there are some additional configuration ste 4. Add `google-services.json` at the root of your project. 5. Add Google Services class path to your app-level Gradle dependencies block `"com.google.gms:google-services:4.4.0"`. 6. Add the Google Services plugin to your app-level Gradle in the plugins block as `"com.google.gms.google-services"`. -7. Add notification handler service to `AndroidManifest.xml` inside the application tag, alongside other activities. Find an example of this service in the [Send push notification](https://appwrite.io/docs/products/messaging/send-push-notifications#add-targets) journey. +7. Add notification handler service to `AndroidManifest.xml` inside the application tag, alongside other activities. Find an example of this service in the [Send push notification](https://appwrite.io/docs/products/messaging/send-push-notifications#add-targets) guide. ```xml From bd5c89b63f8a367d5a693ff0db6d80a26ea23471 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Mon, 29 Jun 2026 19:15:50 +0530 Subject: [PATCH 44/61] Expand paused project deletion changelog with rationale and reassurance --- src/routes/changelog/(entries)/2026-06-29.markdoc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/routes/changelog/(entries)/2026-06-29.markdoc b/src/routes/changelog/(entries)/2026-06-29.markdoc index 23e0bd1b3c5..e4db05efe3e 100644 --- a/src/routes/changelog/(entries)/2026-06-29.markdoc +++ b/src/routes/changelog/(entries)/2026-06-29.markdoc @@ -4,6 +4,8 @@ title: 'Paused free projects are deleted after 90 days' date: 2026-06-29 --- -Free projects are paused after one week of inactivity. A free project that stays paused for 90 days will now be deleted, including all of its resources. +Starting today, free projects that stay paused for 90 days will be deleted, including all of their resources. Affected projects receive email alerts before anything is deleted. + +Reclaiming resources from long-inactive free projects keeps the platform sustainable, affordable, and reliable for everyone building on Appwrite. Projects on Pro and Enterprise plans are never paused or deleted for inactivity, so your production workloads stay untouched. This only applies to projects on free-tier organizations. To keep a paused project, open it in the Appwrite Console to resume it, or upgrade its organization to a paid plan before the 90-day window ends. From f0bf5fa777535d77c314ec27d1712736ae300996 Mon Sep 17 00:00:00 2001 From: Aishwari Pahwa Date: Tue, 30 Jun 2026 13:49:35 +0530 Subject: [PATCH 45/61] latest seo blog for developers --- .optimize-cache.json | 1 + .../+page.markdoc | 119 ++++++++++++++++++ .../cover.avif | Bin 0 -> 10358 bytes 3 files changed, 120 insertions(+) create mode 100644 src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc create mode 100644 static/images/blog/what-is-redis-a-complete-guide-for-developers/cover.avif diff --git a/.optimize-cache.json b/.optimize-cache.json index 9e4bc23df53..074be73c028 100644 --- a/.optimize-cache.json +++ b/.optimize-cache.json @@ -1263,6 +1263,7 @@ "static/images/blog/what-is-mcp/claude-mcp-chat.png": "26842cfebca3ec2cec89448e1c0d7ddb3f5421cc57acdb8780d48d30a54cad82", "static/images/blog/what-is-mcp/claude-mcp-tools.png": "3a5ae700867b8671b5c9e3af61b094aeb64611168463db66ff440e0d427ac6bc", "static/images/blog/what-is-mcp/cover.png": "dc4537990c91d6f1768c5ab8775e5c52239eb901b15e2e74fce8b5a018855c32", + "static/images/blog/what-is-redis-a-complete-guide-for-developers/cover.png": "b7b87a372bbb99421c2ab6df37430da960728b5cf339f1803c432644154c764f", "static/images/blog/when-custom-backend-stops-being-worth-it/cover.png": "d03b13c4e8f3294823a7883cdae89ca18a4030b170c51f597bd139c9ca274793", "static/images/blog/why-ai-generated-apps-need-backend/cover.png": "8761878c13c51dd8a720a625606b89b93d9c56651aed636fa1b2bd346bd4fd82", "static/images/blog/why-developers-choose-appwrite-auth/cover.png": "f56c37ebfc25191e113b928ff3cf144563be740159e46d75a427bdafdd11214b", diff --git a/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc b/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc new file mode 100644 index 00000000000..13202fbeb54 --- /dev/null +++ b/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc @@ -0,0 +1,119 @@ +--- +layout: post +title: What is Redis? A complete guide for developers +description: "Learn what Redis is, why it's so fast, how it works, its data structures, what it's used for, and how it compares to databases, in this guide for developers." +date: 2026-06-30 +cover: /images/blog/what-is-redis-a-complete-guide-for-developers/cover.avif +timeToRead: 5 +author: aditya-oberai +category: architecture +featured: false +unlisted: true +--- + +**Redis is an open-source, in-memory data store used as a database, cache, and message broker, prized for its extreme speed because it keeps data in memory rather than on disk.** Its name stands for Remote Dictionary Server, and it's one of the most popular tools for making applications fast, handling everything from caching to real-time features. + +This guide explains what Redis is, why it's so fast, how it works, the data structures it supports, what it's used for, and how to get started. It's written for developers who want a complete picture, not just a definition. + +# What does Redis do? + +Redis stores data in memory as key-value pairs and serves it back almost instantly. Where a traditional database reads from disk, Redis keeps its data in RAM, which is dramatically faster. This speed makes Redis ideal for any situation where you need to read or write data very quickly, such as caching frequently used results, storing user sessions, or powering real-time features. + +You can think of Redis as the short-term memory of your application. Your main database is like a filing cabinet, reliable but slower to access. Redis is like the notepad on your desk, where you keep the information you need right now so you can grab it instantly. It complements your primary database rather than replacing it. + +Redis is versatile enough to act as a database, a cache, and a message broker, often all at once, which is why it appears in so many production systems. + +# Why is Redis so fast? + +Redis is fast for two main reasons. First, it stores data **in memory** rather than on disk, and reading from RAM is orders of magnitude quicker than reading from a disk. Second, Redis is built around simple, efficient data structures and operations, and it's single-threaded for command execution, which avoids the overhead of managing concurrent access to the same data. + +The result is that Redis can handle a very large number of operations per second with extremely low latency, often under a millisecond. This is why it's the go-to choice for [caching](https://appwrite.io/blog) and other speed-critical tasks. The trade-off is that memory is more limited and more expensive than disk, so Redis is used for data that benefits from being fast to access rather than for storing everything. + +# How does Redis work? + +At its core, Redis is a key-value store: every piece of data is associated with a unique key, and you retrieve data by its key. What makes Redis powerful is that the values aren't limited to simple text. They can be rich data structures like lists, sets, and hashes, each with specialized commands. + +Although Redis keeps data in memory for speed, it can also **persist** data to disk so it isn't lost when the server restarts. It offers two main persistence options: point-in-time snapshots (RDB), which save the dataset periodically, and append-only files (AOF), which log every write operation. You can use either, both, or neither depending on how important durability is for your use case. + +Redis also supports replication, clustering, and expiration of keys, which let it scale and automatically clean up temporary data. + +# What data structures does Redis support? + +One of Redis's defining features is its rich set of data structures, which go far beyond simple strings: + +- **Strings**, the most basic type, holding text or numbers. +- **Lists**, ordered collections useful for queues and timelines. +- **Sets**, unordered collections of unique values, great for membership checks. +- **Sorted sets**, sets ordered by a score, ideal for leaderboards and ranking. +- **Hashes**, maps of field-value pairs, perfect for representing objects. +- **Streams, bitmaps, and more**, for specialized use cases like event logs and counters. + +These structures, combined with fast operations on them, are what let Redis power so many different features elegantly. + +# What is Redis used for? + +Redis appears across a wide range of real-world scenarios: + +- **Caching.** Store frequently accessed data or query results to reduce load on your main database and speed up responses. +- **Session storage.** Keep user session data in a fast, shared store accessible across servers. +- **Real-time analytics and counters.** Increment and read counters instantly for things like views or rate limits. +- **Leaderboards and ranking.** Sorted sets make ranking by score fast and simple. +- **Message queues and pub/sub.** Pass messages between parts of a system or broadcast events in real time. +- **Rate limiting.** Track and limit how often an action happens within a time window. + +# Redis vs traditional databases: what's the difference? + +Redis and a traditional database serve different roles, and they often work together rather than competing. A traditional database (relational or document) stores data on disk durably and is designed for complex queries and long-term storage. Redis stores data in memory for speed and is designed for fast, simple access patterns. + +| Aspect | Redis | Traditional database | +| --- | --- | --- | +| Storage | In memory (with optional disk) | On disk | +| Speed | Extremely fast | Slower for reads | +| Data model | Key-value with rich structures | Tables or documents | +| Querying | Simple, key-based | Complex queries | +| Best for | Caching, real-time, sessions | Durable, primary storage | + +In most architectures, Redis sits in front of or alongside a primary database, handling the fast, frequently accessed data while the main database remains the source of truth. + +# Does Redis lose data if it restarts? + +By default, Redis keeps data in memory, so without persistence configured, data would be lost on restart. However, Redis offers persistence options precisely to prevent this. With RDB snapshots, AOF logging, or both enabled, Redis can recover its dataset after a restart. The right choice depends on your needs: pure caching often doesn't need persistence, while using Redis as a primary store for some data calls for durable persistence. Redis also supports replication, keeping copies on other servers for resilience. + +# How to get started with Redis + +Getting hands-on is the fastest way to understand Redis. + +1. **Install Redis locally** or use a managed Redis service, then connect with the `redis-cli` tool. +2. **Try basic commands** like `SET key value` and `GET key` to store and retrieve data. +3. **Experiment with data structures**, such as pushing to a list or adding to a sorted set. +4. **Set an expiry** on a key with `EXPIRE` to see how Redis handles temporary data, the heart of caching. +5. **Integrate Redis into an app** as a cache in front of your database, and measure the speedup. + +A backend platform like [Appwrite](https://appwrite.io/docs) provides databases, storage, and functions that pair naturally with a caching layer like Redis in a production stack. + +# Redis best practices + +- **Set expiration on cached data** so stale entries clean themselves up and memory stays under control. +- **Choose the right data structure** for each task rather than forcing everything into strings. +- **Plan for memory limits**, since Redis data lives in RAM, and configure an eviction policy. +- **Enable persistence** when you need durability, and replication for resilience. +- **Avoid storing huge values** in single keys, which can hurt performance. +- **Use Redis as a complement** to your primary database, not usually as your only store. + +# Conclusion + +Redis is an in-memory data store that delivers extreme speed by keeping data in memory, making it the go-to tool for caching, sessions, real-time features, and more. Understanding its core pieces, namely the key-value model, the rich data structures it supports, the persistence options that protect data, and how it complements rather than replaces a primary database, gives you the foundation to make applications dramatically faster. Because speed matters in almost every system, Redis is one of the most valuable tools a developer can know. The best way to learn Redis is to install it, run a few commands, and put a cache in front of a real database to feel the difference. + +# Start building + +Appwrite Cloud gives developers a fully managed backend so you can ship fast without provisioning or maintaining any infrastructure. You get auth, databases, storage, functions, and real-time out of the box, scaling automatically as your app grows. Recent releases have added [MongoDB support, Appwrite 1.9.0, realtime upgrades, and new AI tooling](https://dev.to/appwrite/april-product-update-mongodb-support-appwrite-190-realtime-upgrades-and-ai-tooling-1eg6), with [more landing every few weeks](https://dev.to/appwrite/may-product-update-presences-api-rust-runtime-7x-faster-storage-uploads-and-more-9h5). We post weekly roundups of product announcements, AI updates, and [developer insights](https://dev.to/appwrite/weekly-roundup-presences-api-git-deployment-triggers-and-ai-updates-58lj) on the [Appwrite blog](https://appwrite.io/blog) and across our developer channels, so follow along wherever you read. + +Whether you're prototyping your next idea or scaling a production app, Appwrite Cloud gives you a complete backend in one place, with no servers to manage and nothing to set up. [Sign up for Appwrite Cloud](https://cloud.appwrite.io/) and give your next build a real backend to grow on in minutes. + +## Resources + +- [Appwrite documentation](https://appwrite.io/docs) +- [Appwrite integrations](https://appwrite.io/integrations) +- [Appwrite quick start guides](https://appwrite.io/docs/quick-starts) +- [Appwrite on GitHub](https://github.com/appwrite/appwrite) +- [Join the Appwrite Discord](https://appwrite.io/discord) diff --git a/static/images/blog/what-is-redis-a-complete-guide-for-developers/cover.avif b/static/images/blog/what-is-redis-a-complete-guide-for-developers/cover.avif new file mode 100644 index 0000000000000000000000000000000000000000..0aaf9bfd18b5e3bcfefe8ae15fa563b2648a0ce6 GIT binary patch literal 10358 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�?SMykDbuz%XaBrX&ca z^X?}NUgfPO=yW1++i$eTxDGvK?QvEF72#E$Qh_nRLW#yiVO8BCIEPUuJD`UEPBLC9 zP#QW>^YFlInj)Q=Rvb~qZvlGg+i2h%qklG}b0|(uz^)p`V_rGa4wB%N)7m(`B_yxOgMIkGOxR_ar6G&tM!=M9Uc$^OtF24=xZUwK2# ze1cP_@8<-62FwZASwqWN+?{X>b4C<7uh-rRoJ1@|*3))d<_ ziHSZjYBftjyO(sD;Z$lhCGwzYB*S-#v#~(=L=p@8?bEFm`-!3Epn{;uQ%-w@nO=+U zDP*r5wTYdH#x3_WGuM@HD}`BH`lrUJ4HH{B5IJi{$Xc~AU7B#gvo2qRq>15=Kg!wMKRob(y2n7H$J3mSYjcM_gO#*{44paesr4s_OwD|MgC4~@+ zt(-?_>ur^`1T>1y^%qX>r);zs!mN279k*^JqiEpu+nIwrj!O)Tn4mblkpvx4WK--L zgKH3)PEnrnrAWTou)^V$NV(tqnx*Mb$y@S1>Kan`Jg9CYl->@CF>xUl0=`Zns}}EU z_~IQ;Q4HygC|yA9e42+1zIQk^BA6@BJ_r_Rd~9}BWP~ZA+|TNk(8Yy3NooqPq#{Hj z)DXF3FMl(8Fsf-^@@vUQwEW>@v|8WWwf2Ei$?jXhXjpvlXhUXolaDo;^e(;$E*b_N z8!o5PL2ZAxx&ExKd1`^W$laC`lJK0^SIT#)UJkXH0jB99*RwBqZ#$PUFI5?@*Aluy zhOyJ^W4a)o##ewwNbd5-YqHN2(g}4nwFkw`1-8xEVjELNM!Tp|+=E;177TtxY?(Qs zF%@*23Bl-EYm=T}(yBDMYX}LVg<#UHdQ#%g+$e?mlcFJE2?xap68aPT^_IrEgUjv? zc{8t;c(m4UI6SKMg*|I;%c)H#n!Jez;O4Cm2pDn;0CiQrBzT@6bCev-cQD@yZ<>>_ zo0P&L?EMI`MsF3BZ{L_gfl0NWltgBS#qsLntOh@6xm&|W3^nW0MfhI-^aSv-s$XN^ zU(BwI?CmM;=W||n5Q~Wm3}}d7BSyc%&m2UZO&X@I`^mxka?E)B;>3e}gwUDf0lEc_ zm6^D4dafO|cS{ZCD}}Qe0Y5@P73L9ztIwX*sKVU3JcyDHm-E{&bYJxlVWv*RX1cL# z)#RH_=aG&-=TE5j@`WCD$#KA$|>WlP85@;oc0UoUN;$bh}#BqA2Ht zBbL&7;hqlemCyD45dYJHq2@Bon?}^Co%AqiVChsDR2Gkf&Cf`FwTYp2F~am>67TcH zQ<+#R9UZ%+-07O#Aq6)gupvR4WW5vN+iXnZBxlbKDEq4K2I6)V>ld9Qor~GD=5Mv~ zih0TTYpgYlffIJn))4b3r>VvAqdrk^rfa^G`sn5-fy8jqXl;W7zM-t8};0Q#rLS23g&2m#&M`B<&d|c*eHL96y`qS#n05M zjtq^Vv?4FXF_@MFO!mBxhIW+s94iv;sn>-T<%3$hR!l3mi}n!Gk33R7Z^Kb82F5(z zjJ}&jOGc-tKic}S8Ak Date: Tue, 30 Jun 2026 13:53:03 +0530 Subject: [PATCH 46/61] Apply suggestion from @greptile-apps[bot] Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- .../what-is-redis-a-complete-guide-for-developers/+page.markdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc b/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc index 13202fbeb54..36aae894f13 100644 --- a/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc +++ b/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc @@ -27,7 +27,7 @@ Redis is versatile enough to act as a database, a cache, and a message broker, o Redis is fast for two main reasons. First, it stores data **in memory** rather than on disk, and reading from RAM is orders of magnitude quicker than reading from a disk. Second, Redis is built around simple, efficient data structures and operations, and it's single-threaded for command execution, which avoids the overhead of managing concurrent access to the same data. -The result is that Redis can handle a very large number of operations per second with extremely low latency, often under a millisecond. This is why it's the go-to choice for [caching](https://appwrite.io/blog) and other speed-critical tasks. The trade-off is that memory is more limited and more expensive than disk, so Redis is used for data that benefits from being fast to access rather than for storing everything. +The result is that Redis can handle a very large number of operations per second with extremely low latency, often under a millisecond. This is why it's the go-to choice for caching and other speed-critical tasks. The trade-off is that memory is more limited and more expensive than disk, so Redis is used for data that benefits from being fast to access rather than for storing everything. # How does Redis work? From f26f63fdb22ac33283fbe2ecce33ed5d372dc5eb Mon Sep 17 00:00:00 2001 From: Aishwari Pahwa Date: Tue, 30 Jun 2026 13:55:12 +0530 Subject: [PATCH 47/61] Update +page.markdoc --- .../+page.markdoc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc b/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc index 36aae894f13..36bd2bc98f3 100644 --- a/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc +++ b/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc @@ -9,6 +9,15 @@ author: aditya-oberai category: architecture featured: false unlisted: true +faqs: + - question: Is Redis a database or a cache? + answer: Both. Redis is an in-memory data store that can act as a database, a cache, and a message broker. It's most commonly used as a cache, but it's flexible enough to fill all three roles. + - question: Does Redis store data permanently? + answer: It can. By default Redis keeps data in memory, but with persistence options like RDB snapshots or AOF logging enabled, it saves data to disk and can recover after a restart. + - question: What is Redis used for most often? + answer: Caching is the most common use, storing frequently accessed data to speed up applications and reduce database load. It's also widely used for sessions, real-time features, and queues. + - question: Is Redis a SQL or NoSQL database? + answer: Redis is a NoSQL data store. It uses a key-value model with rich data structures rather than the tables and SQL queries of a relational database. --- **Redis is an open-source, in-memory data store used as a database, cache, and message broker, prized for its extreme speed because it keeps data in memory rather than on disk.** Its name stands for Remote Dictionary Server, and it's one of the most popular tools for making applications fast, handling everything from caching to real-time features. From 58ba4d159bbf22e77d9b297ba1076bed516b1bc7 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Tue, 30 Jun 2026 17:52:57 +0530 Subject: [PATCH 48/61] Move 1.9.5 release blog and changelog date to 2026-06-30 --- .../blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc | 2 +- .../(entries)/{2026-06-29.markdoc => 2026-06-30.markdoc} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/routes/changelog/(entries)/{2026-06-29.markdoc => 2026-06-30.markdoc} (98%) diff --git a/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc b/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc index 38fbd104bcb..3c6314af6c2 100644 --- a/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc +++ b/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc @@ -3,7 +3,7 @@ layout: post title: Announcing Appwrite 1.9.5 for self-hosted deployments description: Appwrite 1.9.5 brings the Presences API, BigInt columns, the Rust runtime, X OAuth, email policies, Bun and Deno build runtimes, Git deployment triggers, faster Storage uploads, and broader migrations to self-hosted deployments. cover: /images/blog/appwrite-1-9-5-self-hosted-release/cover.avif -date: 2026-06-29 +date: 2026-06-30 timeToRead: 6 author: chirag-aggarwal category: announcement diff --git a/src/routes/changelog/(entries)/2026-06-29.markdoc b/src/routes/changelog/(entries)/2026-06-30.markdoc similarity index 98% rename from src/routes/changelog/(entries)/2026-06-29.markdoc rename to src/routes/changelog/(entries)/2026-06-30.markdoc index 874e1aea268..72fb76083db 100644 --- a/src/routes/changelog/(entries)/2026-06-29.markdoc +++ b/src/routes/changelog/(entries)/2026-06-30.markdoc @@ -1,7 +1,7 @@ --- layout: changelog title: Announcing Appwrite 1.9.5 for self-hosted deployments -date: 2026-06-29 +date: 2026-06-30 cover: /images/blog/appwrite-1-9-5-self-hosted-release/cover.avif --- From ef27c5df99f8d7d3fe8906724acb76e9156f0672 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Tue, 30 Jun 2026 21:37:10 +0530 Subject: [PATCH 49/61] Remove email policies from 1.9.5 release blog and changelog --- .../+page.markdoc | 14 ++------------ src/routes/changelog/(entries)/2026-06-30.markdoc | 1 - 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc b/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc index 3c6314af6c2..ec17b06d9df 100644 --- a/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc +++ b/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc @@ -1,7 +1,7 @@ --- layout: post title: Announcing Appwrite 1.9.5 for self-hosted deployments -description: Appwrite 1.9.5 brings the Presences API, BigInt columns, the Rust runtime, X OAuth, email policies, Bun and Deno build runtimes, Git deployment triggers, faster Storage uploads, and broader migrations to self-hosted deployments. +description: Appwrite 1.9.5 brings the Presences API, BigInt columns, the Rust runtime, X OAuth, Bun and Deno build runtimes, Git deployment triggers, faster Storage uploads, and broader migrations to self-hosted deployments. cover: /images/blog/appwrite-1-9-5-self-hosted-release/cover.avif date: 2026-06-30 timeToRead: 6 @@ -11,7 +11,7 @@ featured: false callToAction: true faqs: - question: "What is new in Appwrite 1.9.5 for self-hosted deployments?" - answer: "Appwrite 1.9.5 brings the Presences API, BigInt columns for [Databases](/docs/products/databases), the Rust runtime for [Functions](/docs/products/functions), X OAuth and email policies for [Auth](/docs/products/auth), Bun and Deno build runtimes and Git deployment triggers for [Sites](/docs/products/sites), faster Storage uploads with parallel chunks, and broader migration coverage." + answer: "Appwrite 1.9.5 brings the Presences API, BigInt columns for [Databases](/docs/products/databases), the Rust runtime for [Functions](/docs/products/functions), X OAuth for [Auth](/docs/products/auth), Bun and Deno build runtimes and Git deployment triggers for [Sites](/docs/products/sites), faster Storage uploads with parallel chunks, and broader migration coverage." - question: "How do I self-host Appwrite 1.9.5?" answer: "Run the Docker installer with the 1.9.5 image, then open the setup wizard on port 20080 to finish configuration. See the [self-hosting installation guide](/docs/advanced/self-hosting/installation) for the full command and system requirements." - question: "How do I upgrade my self-hosted instance to 1.9.5?" @@ -24,8 +24,6 @@ faqs: answer: "Yes. Appwrite 1.9.5 adds Rust as a first-class [Functions](/docs/products/functions) runtime, so you can write and deploy functions in Rust and pair them with the official Appwrite Rust SDK." - question: "Can I build my Appwrite Sites with Bun or Deno?" answer: "Yes. Appwrite [Sites](/docs/products/sites) can now build Node-based frameworks with Bun or Deno. You can switch the build runtime per Site from its Runtime settings, and the change applies on the next deployment." - - question: "Can I block disposable or free email addresses at signup?" - answer: "Yes. Email policies in [Appwrite Auth](/docs/products/auth) let you block disposable inboxes, aliased addresses, and free email providers at user creation and on email updates, either from the Console or through any server SDK." - question: "How much faster are Storage uploads in 1.9.5?" answer: "Appwrite SDKs now upload Storage file chunks in parallel. In our Node SDK benchmark, a 1.28 GB upload dropped from 4 minutes 44 seconds to under 40 seconds, a 7.10x improvement, with no API changes required." --- @@ -84,14 +82,6 @@ Appwrite Auth now supports signing in with X (formerly Twitter) through OAuth 2. Read the announcement {% /arrow_link %} -# Email policies - -Email policies let you restrict which email addresses can create accounts or update their email. Block disposable inboxes to keep throwaway accounts out of your users table, and deny free providers so business products only accept corporate addresses. Each policy is an independent toggle in the Console or any server SDK. - -{% arrow_link href="/blog/post/announcing-email-policies" %} -Read the announcement -{% /arrow_link %} - # Faster uploads with parallel chunks Appwrite SDKs now upload Storage file chunks in parallel. In our Node SDK benchmark, a 1.28 GB upload dropped from 4 minutes 44 seconds to under 40 seconds, a 7.10x improvement, with no API changes required. diff --git a/src/routes/changelog/(entries)/2026-06-30.markdoc b/src/routes/changelog/(entries)/2026-06-30.markdoc index 72fb76083db..b5d147d4b15 100644 --- a/src/routes/changelog/(entries)/2026-06-30.markdoc +++ b/src/routes/changelog/(entries)/2026-06-30.markdoc @@ -13,7 +13,6 @@ Most notably, this release includes: - BigInt columns for Databases - Rust runtime for Functions - X (formerly Twitter) OAuth support for Auth -- Email policies to block disposable, aliased, and free email addresses - Bun and Deno build runtimes for Sites - Git deployment triggers for Functions and Sites - Parallel chunk uploads for faster Storage uploads From 1bfb99722899f4893adb7c77b6c39898174dfb24 Mon Sep 17 00:00:00 2001 From: Aishwari Pahwa Date: Wed, 1 Jul 2026 12:20:33 +0530 Subject: [PATCH 50/61] Apply suggestion from @aishwaripahwa12 --- .../what-is-redis-a-complete-guide-for-developers/+page.markdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc b/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc index 36bd2bc98f3..833396bce32 100644 --- a/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc +++ b/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc @@ -98,7 +98,7 @@ Getting hands-on is the fastest way to understand Redis. 4. **Set an expiry** on a key with `EXPIRE` to see how Redis handles temporary data, the heart of caching. 5. **Integrate Redis into an app** as a cache in front of your database, and measure the speedup. -A backend platform like [Appwrite](https://appwrite.io/docs) provides databases, storage, and functions that pair naturally with a caching layer like Redis in a production stack. +Appwrite uses Redis-like technology internally for list caching, while developers can still use Redis alongside Appwrite when their own apps need caching, queues, sessions, or fast temporary data. # Redis best practices From 3ec3bd7bcfbe9c2421ccb3068d1dcdd031908809 Mon Sep 17 00:00:00 2001 From: Aishwari Pahwa Date: Wed, 1 Jul 2026 12:28:48 +0530 Subject: [PATCH 51/61] Apply suggestion from @aishwaripahwa12 --- .../what-is-redis-a-complete-guide-for-developers/+page.markdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc b/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc index 833396bce32..93a0f0b2329 100644 --- a/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc +++ b/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc @@ -115,7 +115,7 @@ Redis is an in-memory data store that delivers extreme speed by keeping data in # Start building -Appwrite Cloud gives developers a fully managed backend so you can ship fast without provisioning or maintaining any infrastructure. You get auth, databases, storage, functions, and real-time out of the box, scaling automatically as your app grows. Recent releases have added [MongoDB support, Appwrite 1.9.0, realtime upgrades, and new AI tooling](https://dev.to/appwrite/april-product-update-mongodb-support-appwrite-190-realtime-upgrades-and-ai-tooling-1eg6), with [more landing every few weeks](https://dev.to/appwrite/may-product-update-presences-api-rust-runtime-7x-faster-storage-uploads-and-more-9h5). We post weekly roundups of product announcements, AI updates, and [developer insights](https://dev.to/appwrite/weekly-roundup-presences-api-git-deployment-triggers-and-ai-updates-58lj) on the [Appwrite blog](https://appwrite.io/blog) and across our developer channels, so follow along wherever you read. +Appwrite Cloud gives developers a fully managed backend so you can ship fast without provisioning or maintaining any infrastructure. You get Auth, Databases, Storage, Functions, Sites, and Realtime out of the box, scaling automatically as your app grows. Recent releases have added [MongoDB support, Appwrite 1.9.0, realtime upgrades, and new AI tooling](https://dev.to/appwrite/april-product-update-mongodb-support-appwrite-190-realtime-upgrades-and-ai-tooling-1eg6), with [more landing every few weeks](https://dev.to/appwrite/may-product-update-presences-api-rust-runtime-7x-faster-storage-uploads-and-more-9h5). We post weekly roundups of product announcements, AI updates, and [developer insights](https://dev.to/appwrite/weekly-roundup-presences-api-git-deployment-triggers-and-ai-updates-58lj) on the [Appwrite blog](https://appwrite.io/blog) and across our developer channels, so follow along wherever you read. Whether you're prototyping your next idea or scaling a production app, Appwrite Cloud gives you a complete backend in one place, with no servers to manage and nothing to set up. [Sign up for Appwrite Cloud](https://cloud.appwrite.io/) and give your next build a real backend to grow on in minutes. From 2ce646f959f8e4401086499a240aca0432605526 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Wed, 1 Jul 2026 14:06:46 +0530 Subject: [PATCH 52/61] Apply suggestions from code review Co-authored-by: Atharva Deosthale --- .../+page.markdoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc b/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc index 93a0f0b2329..f7367fed43f 100644 --- a/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc +++ b/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc @@ -121,8 +121,8 @@ Whether you're prototyping your next idea or scaling a production app, Appwrite ## Resources -- [Appwrite documentation](https://appwrite.io/docs) -- [Appwrite integrations](https://appwrite.io/integrations) -- [Appwrite quick start guides](https://appwrite.io/docs/quick-starts) +- [Appwrite documentation](/docs) +- [Appwrite integrations](/integrations) +- [Appwrite quick start guides](/docs/quick-starts) - [Appwrite on GitHub](https://github.com/appwrite/appwrite) - [Join the Appwrite Discord](https://appwrite.io/discord) From 6c2967ff372c4a2375db62ebdeaec9d7ea392755 Mon Sep 17 00:00:00 2001 From: Aishwari Pahwa Date: Wed, 1 Jul 2026 15:49:35 +0530 Subject: [PATCH 53/61] latest anthropic release --- .optimize-cache.json | 1 + .../+page.markdoc | 127 ++++++++++++++++++ .../cover.avif | Bin 0 -> 17932 bytes 3 files changed, 128 insertions(+) create mode 100644 src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc create mode 100644 static/images/blog/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/cover.avif diff --git a/.optimize-cache.json b/.optimize-cache.json index 6d36dfa8aed..f4183842e66 100644 --- a/.optimize-cache.json +++ b/.optimize-cache.json @@ -483,6 +483,7 @@ "static/images/blog/claude-fable-5-and-mythos-5-access-suspended/cover.avif": "f6c50bbd5f1eaabef50803b5b76792f8f5f7a2fb009ed8670a08cd9ad1f23971", "static/images/blog/claude-mythos-preview/cover.png": "aea7b0c45c492939048fbf04a9b001b96c7bf727bcf7e5afc8274f84644dd35d", "static/images/blog/claude-mythos-release-date-what-we-know-so-far/cover.png": "0197caa87f00bc03063fb2b1872052cf02733298b2991871852762f32fcfa202", + "static/images/blog/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/cover.png": "15a3350966c037f6747c4b3626e9770ba4ee8065439702903ee3cde13a4573e2", "static/images/blog/claude-vs-gpt-vs-gemini-for-developers-who-wins-in-2026/cover.png": "b931411d483646bcc79649dfc518e86fa4768504b13dbd3d03885c9a2bbde531", "static/images/blog/client-dashboards-internal-tools/cover.png": "d758f2f517487e24037cef5b3e9036ade6c238cd2f216ef6c76ce5467c665d92", "static/images/blog/client-vs-server-components-react/cover.png": "b7ae8b7614902c8b4dd7826d59cfdb36db9abbe27bde99b3deb69c4bf178f425", diff --git a/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc b/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc new file mode 100644 index 00000000000..596c1c4c50d --- /dev/null +++ b/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc @@ -0,0 +1,127 @@ +--- +layout: post +title: "Claude Sonnet 5 is Anthropic's most agentic Sonnet yet" +description: "Claude Sonnet 5 is Anthropic's most agentic Sonnet model, nearing Opus 4.8 performance at lower prices. See benchmarks, pricing, and how to build on Appwrite." +date: 2026-07-01 +cover: /images/blog/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/cover.avif +timeToRead: 5 +author: aishwari +category: ai +featured: false +faqs: + - question: When was Claude Sonnet 5 released? + answer: Anthropic launched Claude Sonnet 5 on June 30, 2026. It is available everywhere from day one, including Claude Code, the Claude Platform, and the Claude API. + - question: How much does Claude Sonnet 5 cost? + answer: Claude Sonnet 5 launched with introductory pricing of $2 per million input tokens and $10 per million output tokens through August 31, 2026. After that it moves to standard pricing of $3 per million input tokens and $15 per million output tokens. For reference, Opus 4.8 costs $5 input and $25 output per million tokens. + - question: What is new in Claude Sonnet 5 compared with Sonnet 4.6? + answer: Better reasoning, tool use, coding, and knowledge work. It is more persistent on long tasks, checks its own output, and is safer overall. + - question: Is Claude Sonnet 5 good for coding? + answer: Yes. It scores 63.2% on SWE-bench Pro and 80.4% on Terminal-Bench 2.1, close to Opus 4.8 and well ahead of Sonnet 4.6. + - question: Is Claude Sonnet 5 free? + answer: Yes, in the consumer apps. Claude Sonnet 5 is the default model on the Free and Pro plans, and is also available to Max, Team, and Enterprise users. Developers who call it through the Claude API pay per token at the rates above. +--- +Anthropic just [launched Claude Sonnet 5](https://www.anthropic.com/news/claude-sonnet-5), the most agentic Sonnet model it has released. It can make plans, drive tools like browsers and terminals, and run autonomously on work that only a few months ago demanded larger, more expensive models. For anyone building agents, that shift matters. The capability you used to reach for an Opus-class model to get is now available in a Sonnet-class one, at a Sonnet-class price. You call it through the Claude API with the model id `claude-sonnet-5`. + +The agentic AI era arguably started with Sonnet-class models. Claude Sonnet 3.5, 3.6, and 3.7 were the first to show serious skill at coding and tool use. Since then, the sharpest gains had been concentrated in Opus-class models. Claude Sonnet 5 narrows that gap: its performance lands close to Opus 4.8 on many tasks, while carrying lower input and output token pricing than Opus 4.8. + +# What is Claude Sonnet 5? + +Claude Sonnet 5 is Anthropic's newest mid-tier model and the successor to Claude Sonnet 4.6. It's a substantial upgrade on the aspects of agentic performance that developers care about most: reasoning, tool use, coding, and knowledge work. The headline is efficiency. Sonnet 5 gets close to Opus 4.8 quality on a range of tasks while staying priced as a Sonnet, which makes it the natural default for high-volume, long-running agent workloads where cost per run adds up fast. + +It's available everywhere from launch. Sonnet 5 is the default model on Free and Pro plans, and is available to Max, Team, and Enterprise users. It also ships in Claude Code and on the Claude Platform, and developers can call it directly via the Claude API. + +One implementation detail worth knowing before you migrate: Sonnet 5 uses an updated tokenizer (the same change Anthropic introduced with Claude Opus 4.7). It changes how the model processes text to improve performance, with the tradeoff that the same input can map to more tokens, roughly 1.0 to 1.35 times as many depending on the content type. Anthropic set the introductory pricing so that moving from Sonnet 4.6 to Sonnet 5 is roughly cost-neutral despite this. + +# Claude Sonnet 5 benchmarks + +Anthropic published a benchmark table comparing Sonnet 5 against its predecessor Sonnet 4.6 and against Opus 4.8, which sits above it as a more generally capable reference model. Across the board, Sonnet 5 improves on Sonnet 4.6 and closes much of the distance to Opus 4.8. + +| Benchmark | Claude Sonnet 5 | Claude Sonnet 4.6 | Claude Opus 4.8 (for reference) | +| -------------------------------------------------------------- | --------------- | ----------------- | ------------------------------- | +| Agentic coding (SWE-bench Pro) | 63.2% | 58.1% | **69.2%** | +| Agentic coding (Terminal-Bench 2.1) | 80.4% | 67.0% | **82.7%** | +| Multidisciplinary reasoning (Humanity's Last Exam, no tools) | 43.2% | 34.6% | **49.8%** | +| Multidisciplinary reasoning (Humanity's Last Exam, with tools) | 57.4% | 46.8% | **57.9%** | +| Computer use (OSWorld-Verified) | 81.2% | 78.5% | **83.4%** | +| Knowledge work (GDPval-AA v2) | **1618** | 1395 | 1615 | + +*Scores for Sonnet 5 on a range of evaluations compared with Sonnet 4.6 and Opus 4.8 (a more generally capable model, shown for reference). The* [Claude Sonnet 5 System Card](https://www.anthropic.com/news/claude-sonnet-5) *reports a broader set of evaluations in detail.* + +**The pattern** + +* Sonnet 5 beats Sonnet 4.6 on every benchmark, often by a wide margin, and lands within a few points of Opus 4.8 on most of them. +* Terminal-Bench 2.1: 80.4% vs Opus 4.8's 82.7%. +* OSWorld-Verified: 81.2% vs 83.4%. +* Knowledge work (GDPval-AA v2): edges past Opus 4.8, 1618 to 1615. +* Clearest remaining gap: the harder SWE-bench Pro coding tasks, where Opus 4.8 still leads. + +**A note on shifting reference numbers** + +* A couple of these reference numbers moved recently for methodology reasons, so it's worth being precise. +* Anthropic updated the grader model for Humanity's Last Exam, so Sonnet 4.6 now sits at 34.6% (no tools) and 46.8% (with tools) rather than its original launch figures. +* Changes to how OSWorld-Verified is run, meant to better reflect real-world performance, moved Sonnet 4.6's score to 78.5%. +* If you compare against older blog posts, expect small discrepancies for exactly this reason. + +# How Claude Sonnet 5 compares to Opus 4.8 + +The most useful way to think about Sonnet 5 is not as a cheaper Sonnet upgrade, but as part of Anthropic's newer 5-series generation, alongside models like Fable 5. It is more capable than Sonnet 4.6 and has lower per-token pricing than Opus 4.8, but that does not automatically make every run cheaper. + +Anthropic lets developers adjust the effort level, from lower settings for faster runs up to max mode for harder tasks that need deeper reasoning. That matters because total cost depends on more than token price. If Sonnet 5 uses significantly more tokens on a long agent workflow or benchmark run, it can still end up costing more overall. + +The practical takeaway is to treat cost as a mix of model price, total tokens used, and effort level: + +* Use lower or medium effort for high-volume tasks where speed and cost control matter. +* Use max mode only when the task genuinely needs stronger reasoning or longer autonomous work. +* Do not assume Sonnet 5 is cheaper overall just because its per-token pricing is lower than Opus 4.8. + +# What Claude Sonnet 5 is good at + +Anthropic's early-access partners were consistent in their feedback: Sonnet 5 is much more agentic than its predecessors. The concrete behaviors they highlighted map neatly onto what an agent actually needs to do. + +* **Finishing long tasks.** Testers described Sonnet 5 completing complex, multi-step tasks where previous Sonnet models would stop short. That persistence across a long chain of steps is exactly what separates a usable agent from one that needs constant hand-holding. +* **Checking its own work.** Partners noted that Sonnet 5 verifies its own output without being explicitly told to. Self-checking is a small behavior with an outsized effect on reliability, because it catches errors before they compound down the chain. +* **Tool use and reasoning.** The gains over Sonnet 4.6 in tool use, reasoning, and coding are what let it operate browsers and terminals autonomously and recover when a step doesn't go as planned. + +# Claude Sonnet 5's safety and safeguards + +* Anthropic's pre-deployment evaluations found Sonnet 5 to be an overall improvement on Sonnet 4.6 for safety. It's better at refusing malicious requests and at resisting hijack attempts in prompt injection attacks, a meaningful property for agents that read untrusted web content or tool output. It also shows lower rates of hallucination and sycophancy than Sonnet 4.6. +* On Anthropic's automated behavioral audit, which tests for a wide range of misaligned behaviors such as cooperation with misuse and deception, Sonnet 5 scored lower (that is, safer) overall than Sonnet 4.6. It did show somewhat higher rates of misaligned behavior than the more capable Opus 4.8 and Claude Mythos Preview, which is the expected pattern for a smaller model. +* On cybersecurity, the key point is that Sonnet 5 simply isn't that capable of causing cyber harm. Anthropic did not deliberately train it on cyber tasks. It can handle routine, non-harmful cyber work but performs substantially worse than Opus 4.8 and Mythos 5 on potentially dangerous skills such as developing software exploits. On an evaluation built with Mozilla that tested exploit development against Firefox vulnerabilities (since patched), Sonnet 5 never produced a full working exploit. It showed a slightly higher partial-success rate than Sonnet 4.6, a shift Anthropic attributes to general intelligence gains rather than any cyber-specific training. +* Because Sonnet 5 is somewhat stronger than its predecessor here, it launches with cyber safeguards enabled by default. These are the same real-time detection-and-blocking safeguards present in Claude Opus 4.7 and 4.8, and they're deliberately less strict than the safeguards shipped with Fable 5, reflecting Anthropic's judgment that Sonnet 5's overall cyber risk is low. Sonnet 5 is also part of Anthropic's Cyber Verification Program. + +# Claude Sonnet 5 pricing + +Claude Sonnet 5 launches with introductory pricing, per million tokens: + +* **Input:** $2 +* **Output:** $10 + +That introductory rate runs through **August 31, 2026**, after which it moves to standard pricing of **$3 per million input tokens and $15 per million output tokens**. For comparison, Opus 4.8 is priced at $5 input and $25 output per million tokens. + +Keep the tokenizer change in mind when you model your bill: because the same input can map to more tokens under Sonnet 5's tokenizer, the introductory pricing is calibrated to keep the transition from Sonnet 4.6 roughly cost-neutral. Anthropic also raised rate limits across Chat, Cowork, Claude Code, and the Claude Platform to accommodate the higher token usage that comes with higher effort levels. + +# Claude Sonnet 5 availability + +Sonnet 5 is available everywhere today. It's the default model on Free and Pro plans and is available to Max, Team, and Enterprise users. Developers can reach it in Claude Code and on the Claude Platform, and call it directly through the Claude API using the model id `claude-sonnet-5`. There's no staged rollout to wait through, so you can start building on it now. + +# What this means if you build on Appwrite + +Sonnet 5's biggest strength is long-horizon, autonomous work at a price that makes running it at scale realistic: agents that plan, use tools, check their own output, and keep going across many steps. An agent doing that kind of work needs somewhere to authenticate users, store state, persist files between steps, and run server-side logic. In other words, it needs a backend, and wiring one up by hand is usually the slow part of shipping an agentic app. + +If you want your Sonnet 5 powered agent to stand up that backend without manually assembling infrastructure, the [Appwrite plugin for Claude Code](https://appwrite.io/docs/tooling/claude-code) bundles the [Appwrite API MCP server](https://appwrite.io/docs/tooling/mcp), the Appwrite Docs MCP server, and SDK-specific agent skills into a single install. With the right project access and permissions, an agent can work directly with Appwrite APIs and docs to set up [Auth](https://appwrite.io/docs/products/auth), [Databases](https://appwrite.io/docs/products/databases), [Storage](https://appwrite.io/docs/products/storage), [Sites](https://appwrite.io/docs/products/sites), and [Functions](https://appwrite.io/docs/products/functions). + +Because Sonnet 5 lets you tune effort against cost, it pairs especially well with high-volume agent workloads: run at medium effort for the bulk of routine steps, and dial up only when a task genuinely needs it. + +# Build agentic apps on Appwrite + +Spin up the backend your next app needs in minutes. Start for free on Appwrite Cloud, connect the Claude API with the model id `claude-sonnet-5`, and let Appwrite handle Auth, Databases, Storage, Functions, Messaging, and Sites. Your Sonnet 5 agent builds the app, Appwrite runs the backend behind it, and you ship the product instead of wiring up infrastructure. + +Recent releases have added [MongoDB support, Appwrite 1.9.0, realtime upgrades, and new AI tooling](https://dev.to/appwrite/april-product-update-mongodb-support-appwrite-190-realtime-upgrades-and-ai-tooling-1eg6), with [more landing every few weeks](https://dev.to/appwrite/may-product-update-presences-api-rust-runtime-7x-faster-storage-uploads-and-more-9h5). We post weekly roundups of product announcements, AI updates, and [developer insights](https://dev.to/appwrite/weekly-roundup-presences-api-git-deployment-triggers-and-ai-updates-58lj) on the [Appwrite blog](https://appwrite.io/blog) and across our developer channels, so follow along wherever you read. + +# Resources + +* [Appwrite MCP server docs](https://appwrite.io/docs/tooling/ai/mcp-servers/docs) +* [Start building on Appwrite Cloud](https://cloud.appwrite.io/) +* [Appwrite AI products](https://appwrite.io/docs/tooling/ai) +* [Appwrite integrations](https://appwrite.io/integrations) +* [Join the Appwrite Discord](https://appwrite.io/discord) \ No newline at end of file diff --git a/static/images/blog/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/cover.avif b/static/images/blog/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/cover.avif new file mode 100644 index 0000000000000000000000000000000000000000..ec3880fb6f8fc329d41d2f84109898b98dc9a52d GIT binary patch literal 17932 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 literal 0 HcmV?d00001 From e52ad2b045fed327b605a75ef20ca17096823526 Mon Sep 17 00:00:00 2001 From: Aishwari Pahwa Date: Wed, 1 Jul 2026 16:10:01 +0530 Subject: [PATCH 54/61] Update +page.markdoc --- .../+page.markdoc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc b/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc index 596c1c4c50d..d28d6c70b08 100644 --- a/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc +++ b/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc @@ -66,7 +66,7 @@ Anthropic published a benchmark table comparing Sonnet 5 against its predecessor The most useful way to think about Sonnet 5 is not as a cheaper Sonnet upgrade, but as part of Anthropic's newer 5-series generation, alongside models like Fable 5. It is more capable than Sonnet 4.6 and has lower per-token pricing than Opus 4.8, but that does not automatically make every run cheaper. -Anthropic lets developers adjust the effort level, from lower settings for faster runs up to max mode for harder tasks that need deeper reasoning. That matters because total cost depends on more than token price. If Sonnet 5 uses significantly more tokens on a long agent workflow or benchmark run, it can still end up costing more overall. +Anthropic lets developers adjust the effort level, from lower settings for faster runs up to max mode for harder tasks that need deeper reasoning. The important caveat is that Sonnet 5 tends to spend far more tokens at higher reasoning levels, so lower per-token pricing does not always mean lower task cost. In Artificial Analysis' benchmark, Sonnet 5 at max effort cost more per task than Opus 4.8 at standard pricing and also cost more to run than Fable 5 in the referenced comparison. That makes the tradeoff less about "cheap Sonnet vs expensive Opus" and more about choosing the right effort level for the workload. The practical takeaway is to treat cost as a mix of model price, total tokens used, and effort level: @@ -84,6 +84,8 @@ Anthropic's early-access partners were consistent in their feedback: Sonnet 5 is # Claude Sonnet 5's safety and safeguards +More autonomy also raises the bar for safety. Since Sonnet 5 is designed for tool-heavy agentic work, Anthropic evaluated how well it handles malicious requests, prompt injection, hallucination, sycophancy, and cyber misuse. + * Anthropic's pre-deployment evaluations found Sonnet 5 to be an overall improvement on Sonnet 4.6 for safety. It's better at refusing malicious requests and at resisting hijack attempts in prompt injection attacks, a meaningful property for agents that read untrusted web content or tool output. It also shows lower rates of hallucination and sycophancy than Sonnet 4.6. * On Anthropic's automated behavioral audit, which tests for a wide range of misaligned behaviors such as cooperation with misuse and deception, Sonnet 5 scored lower (that is, safer) overall than Sonnet 4.6. It did show somewhat higher rates of misaligned behavior than the more capable Opus 4.8 and Claude Mythos Preview, which is the expected pattern for a smaller model. * On cybersecurity, the key point is that Sonnet 5 simply isn't that capable of causing cyber harm. Anthropic did not deliberately train it on cyber tasks. It can handle routine, non-harmful cyber work but performs substantially worse than Opus 4.8 and Mythos 5 on potentially dangerous skills such as developing software exploits. On an evaluation built with Mozilla that tested exploit development against Firefox vulnerabilities (since patched), Sonnet 5 never produced a full working exploit. It showed a slightly higher partial-success rate than Sonnet 4.6, a shift Anthropic attributes to general intelligence gains rather than any cyber-specific training. @@ -122,6 +124,6 @@ Recent releases have added [MongoDB support, Appwrite 1.9.0, realtime upgrades, * [Appwrite MCP server docs](https://appwrite.io/docs/tooling/ai/mcp-servers/docs) * [Start building on Appwrite Cloud](https://cloud.appwrite.io/) -* [Appwrite AI products](https://appwrite.io/docs/tooling/ai) +* [Appwrite AI tooling](https://appwrite.io/docs/tooling/ai) * [Appwrite integrations](https://appwrite.io/integrations) -* [Join the Appwrite Discord](https://appwrite.io/discord) \ No newline at end of file +* [Join the Appwrite Discord](https://appwrite.io/discord) From ce46f1b30d012662f1527d859be0608d038fb569 Mon Sep 17 00:00:00 2001 From: Aishwari Pahwa Date: Wed, 1 Jul 2026 16:15:42 +0530 Subject: [PATCH 55/61] Apply suggestion from @atharvadeosthale Co-authored-by: Atharva Deosthale --- .../+page.markdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc b/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc index d28d6c70b08..bb22a96d9ce 100644 --- a/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc +++ b/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc @@ -66,7 +66,7 @@ Anthropic published a benchmark table comparing Sonnet 5 against its predecessor The most useful way to think about Sonnet 5 is not as a cheaper Sonnet upgrade, but as part of Anthropic's newer 5-series generation, alongside models like Fable 5. It is more capable than Sonnet 4.6 and has lower per-token pricing than Opus 4.8, but that does not automatically make every run cheaper. -Anthropic lets developers adjust the effort level, from lower settings for faster runs up to max mode for harder tasks that need deeper reasoning. The important caveat is that Sonnet 5 tends to spend far more tokens at higher reasoning levels, so lower per-token pricing does not always mean lower task cost. In Artificial Analysis' benchmark, Sonnet 5 at max effort cost more per task than Opus 4.8 at standard pricing and also cost more to run than Fable 5 in the referenced comparison. That makes the tradeoff less about "cheap Sonnet vs expensive Opus" and more about choosing the right effort level for the workload. +Anthropic lets developers adjust the effort level, from lower settings for faster runs up to max mode for harder tasks that need deeper reasoning. The important caveat is that Sonnet 5 tends to spend far more tokens at higher reasoning levels, so lower per-token pricing does not always mean lower task cost. In Artificial Analysis' benchmark, Sonnet 5 at max effort cost more overall than Fable 5 and Opus 4.8, officially being the most expensive model on their benchmark. That makes the tradeoff less about "cheap Sonnet vs expensive Opus" and more about choosing the right effort level for the workload. The practical takeaway is to treat cost as a mix of model price, total tokens used, and effort level: From 1382657bb5d17946c13229f4c37176a0d0a05feb Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Wed, 1 Jul 2026 16:16:43 +0530 Subject: [PATCH 56/61] Apply suggestions from code review Co-authored-by: Atharva Deosthale --- .../+page.markdoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc b/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc index bb22a96d9ce..386d2f54561 100644 --- a/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc +++ b/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc @@ -122,8 +122,8 @@ Recent releases have added [MongoDB support, Appwrite 1.9.0, realtime upgrades, # Resources -* [Appwrite MCP server docs](https://appwrite.io/docs/tooling/ai/mcp-servers/docs) +* [Appwrite MCP server docs](/docs/tooling/ai/mcp-servers/) * [Start building on Appwrite Cloud](https://cloud.appwrite.io/) -* [Appwrite AI tooling](https://appwrite.io/docs/tooling/ai) -* [Appwrite integrations](https://appwrite.io/integrations) +* [Appwrite AI tooling](/docs/tooling/ai) +* [Appwrite integrations](/integrations) * [Join the Appwrite Discord](https://appwrite.io/discord) From a7980a9883689e1a6a237cec05bb8128398ac21f Mon Sep 17 00:00:00 2001 From: Aishwari Pahwa Date: Thu, 2 Jul 2026 11:17:28 +0530 Subject: [PATCH 57/61] latest anthropic update --- .optimize-cache.json | 1 + .../+page.markdoc | 130 ++++++++++++++++++ .../cover.avif | Bin 0 -> 5641 bytes 3 files changed, 131 insertions(+) create mode 100644 src/routes/blog/post/claude-fable-5-returns-with-stronger-jailbreak-safeguards/+page.markdoc create mode 100644 static/images/blog/claude-fable-5-returns-with-stronger-jailbreak-safeguards/cover.avif diff --git a/.optimize-cache.json b/.optimize-cache.json index f4183842e66..bbc57f5e6c4 100644 --- a/.optimize-cache.json +++ b/.optimize-cache.json @@ -481,6 +481,7 @@ "static/images/blog/claude-code-tips-tricks/cover.png": "df329d51541267d46b2b913c376cca27c7ddf12b6a2a36986d418ec41253ddc9", "static/images/blog/claude-design/cover.png": "7530f6d1c1a999089f2a68038d6a17d9953435afb1535d09b462b485f77ce1df", "static/images/blog/claude-fable-5-and-mythos-5-access-suspended/cover.avif": "f6c50bbd5f1eaabef50803b5b76792f8f5f7a2fb009ed8670a08cd9ad1f23971", + "static/images/blog/claude-fable-5-returns-with-stronger-jailbreak-safeguards/cover.png": "bfe441fb7c04a21cb431119065ae05f2c1b044d9885cba7ef3651290f2ff3bb3", "static/images/blog/claude-mythos-preview/cover.png": "aea7b0c45c492939048fbf04a9b001b96c7bf727bcf7e5afc8274f84644dd35d", "static/images/blog/claude-mythos-release-date-what-we-know-so-far/cover.png": "0197caa87f00bc03063fb2b1872052cf02733298b2991871852762f32fcfa202", "static/images/blog/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/cover.png": "15a3350966c037f6747c4b3626e9770ba4ee8065439702903ee3cde13a4573e2", diff --git a/src/routes/blog/post/claude-fable-5-returns-with-stronger-jailbreak-safeguards/+page.markdoc b/src/routes/blog/post/claude-fable-5-returns-with-stronger-jailbreak-safeguards/+page.markdoc new file mode 100644 index 00000000000..38003da4f08 --- /dev/null +++ b/src/routes/blog/post/claude-fable-5-returns-with-stronger-jailbreak-safeguards/+page.markdoc @@ -0,0 +1,130 @@ +--- +layout: post +title: Claude Fable 5 returns with stronger jailbreak safeguards +description: Claude Fable 5 is back after export controls lifted, now with an upgraded jailbreak safety classifier and deeper US government collaboration. +date: 2026-07-02 +cover: /images/blog/claude-fable-5-returns-with-stronger-jailbreak-safeguards/cover.avif +timeToRead: 5 +author: aishwari +category: ai +featured: false +faqs: + - question: Why was Claude Fable 5 suspended? + answer: On June 12, the US government applied export controls to both models, requiring Anthropic to restrict access for foreign nationals. Because the order took effect immediately and there was no reliable way to verify nationality in real time, Anthropic suspended access to both models for everyone. + - question: Is Claude Fable 5 available again? + answer: Yes. As of June 30 the export controls were lifted, and Fable 5 is available again starting Wednesday, July 1, to users globally on the Claude Platform, Claude.ai, Claude Code, and Claude Cowork. + - question: What happened to Claude Fable 5? + answer: Anthropic released Fable 5 and Mythos 5 on June 9. The US government applied export controls on June 12, forcing a full suspension. Those controls were lifted June 30, and Fable 5 is rolling back out globally. + - question: What jailbreak was found in Claude Fable 5? + answer: Amazon researchers found a technique that prompted the model to identify a number of software vulnerabilities, and in one case the model produced code demonstrating how a specific vulnerability could be exploited. Anthropic classified it as a minor jailbreak involving routine defensive cybersecurity work. + - question: What is the difference between Claude Fable 5 and Mythos 5? + answer: They share the same underlying model but differ in how safeguards are applied. Fable 5 shipped with strong safeguards for general use, while Mythos 5 launched with fewer safeguards to a small number of trusted Project Glasswing partners for defensive cybersecurity work. +--- +Claude Fable 5 is back. After a little over two weeks offline, Anthropic has [redeployed](https://www.anthropic.com/news/redeploying-fable-5) its most capable generally available model following the removal of US export controls that had forced a full suspension. Starting Wednesday, July 1, Fable 5 is available again to users worldwide, and it returns with an upgraded safety classifier, a proposed industry framework for scoring jailbreaks, and a deeper set of commitments to the US government. + +If you build on Fable 5, or you were mid-project when it went dark on June 12, here is what changed, why it happened, and what the redeployment means for the way you build. + +# What happened to Claude Fable 5? + +The short version is a timeline. Anthropic released Claude Fable 5 and Claude Mythos 5 on Tuesday, June 9. The two share the same underlying model but differ in how safeguards are applied: Fable 5 shipped with strong safeguards for general use, while Mythos 5 launched with fewer safeguards to a small number of trusted Project Glasswing partners for defensive cybersecurity work. + +On Friday, June 12, the US government applied export controls to both models. Those controls required Anthropic to restrict access for foreign nationals, whether inside or outside the United States. Because the order took effect immediately and there was no reliable way to verify nationality in real time, Anthropic suspended access to both models for everyone. + +As of June 30, those export controls have been lifted. Fable 5 is rolling back out globally, and access to Mythos 5 has been restored for a set of US organizations after the government's approval on June 26. + +# Why were Fable 5 and Mythos 5 suspended? + +The export control directive followed a report from Amazon researchers who found a way to bypass Fable 5's safeguards. The technique prompted the model so that it identified a number of software vulnerabilities, and in one case the model produced code demonstrating how a specific vulnerability could be exploited. + +Over the following two weeks, Anthropic worked with the government and partners, including Amazon, to review the report and the evidence behind it. The suspension was a direct consequence of the export order taking effect with no real-time nationality check available, so the safest option was to pull access for all users rather than risk non-compliance. + +# What the investigation found + +The review put the reported bypass in context, and the findings are worth reading closely if you're trying to gauge real risk. + +Anthropic's testing confirmed that many less capable models could identify the same vulnerabilities that Fable 5 did in the report, including Claude Opus 4.8, GPT-5.5, and Kimi K2.7. When it came to the single demonstration of how to exploit a vulnerability, every model tested could produce the same demonstration as Fable 5. That list included Claude Haiku 4.5, Sonnet 4.6, Opus 4.6, Opus 4.7, and Opus 4.8, alongside GPT-5.4, GPT-5.5, and Kimi K2.7. + +Crucially, the reported technique did not expose any unique Mythos-level cyber capabilities. It reflected a borderline case for Fable 5's safeguards. As explained below, some tasks are unlikely to be dangerous but are still blocked out of an abundance of caution, and the reported technique only reached one such behavior, which involved routine defensive cybersecurity work. + +# Claude Fable 5's new safety classifier + +Even though the bypass touched only routine defensive work, Anthropic moved quickly to close it. Working with the government, the team trained an improved safety classifier that targets and blocks the behavior described in the Amazon report. + +For builders, the practical mechanics matter: + +* If a request to Fable 5 is blocked, the user is notified. +* The blocked request is then sent to Claude Opus 4.8 instead. +* The new classifier blocks the specific technique from the report in over 99% of cases. + +In a very small fraction of cases, the model may still return information, but not detailed enough to help a cyberattacker. Researchers from the US Department of Commerce's Center for AI Standards and Innovation (CAISI) tested both the prior and the new safeguards and agreed they are extraordinarily strong. + +There is a tradeoff. The new classifier flags benign requests more often during routine coding and debugging. Anthropic says it will keep refining the classifier to better separate genuine misuse from legitimate requests and to reduce false positives. + +# How Anthropic's cybersecurity safeguards work + +To understand why a routine coding request can occasionally get caught, it helps to understand the safeguard design. Fable 5 launched with the strongest safeguards Anthropic has ever applied to a model, and in the month before launch the company doubled the number of researchers and engineers on the problem by moving staff across teams. + +## Defense in depth + +No single mechanism provides perfect protection, so Fable 5 stacks several. Some defenses train the model to decline dangerous requests. Others retroactively analyze patterns of misuse. Combined, they make the model very difficult to misuse. + +## Classifiers and the safety margin + +One of the most important mechanisms is the classifier: a smaller automated AI system that detects, during an interaction, when the model is asked to perform a potentially harmful cybersecurity task or produce a potentially harmful output. When that happens, the classifier blocks the model from responding. The goal is to stop uniquely dangerous behaviors. + +Because classifiers can miss content or be jailbroken, Anthropic deliberately tunes them to trigger on some requests that are likely benign. A request has to look very clearly safe to avoid tripping the classifier, which users experience as the model declining some reasonable, non-harmful requests. This buffer is the "safety margin." For Fable 5, that margin was set much larger than in any prior launch, so more benign requests get blocked, but fewer genuinely harmful ones slip through. This is the deliberate tradeoff that keeps the rest of Fable 5's capabilities widely available. + +## How jailbreaks are categorized + +The safety margin also helps blunt jailbreaks, and Anthropic sorts them by severity: + +* **Minor jailbreaks** unblock behavior that still sits inside the safety margin. It is very unlikely to be harmful. Anthropic's view is that the jailbreaks reported for Fable 5 so far fall into this category. +* **Narrow harmful jailbreaks** breach the classifiers to unlock a specific harmful behavior. These are typically low to moderate severity because their narrowness limits the attacker. +* **Universal jailbreaks** unblock a whole class of harmful behaviors and are the most concerning. + +Anthropic is candid that it is probably impossible to make any model fully impervious to jailbreaks. It expects many minor ones and some narrow harmful ones over time. At the time of writing, no universal jailbreaks for Fable 5 have been discovered, and expert red-teamers continue to probe it. The aim is for Anthropic and its safety partners to find and fix major jailbreaks before malicious actors can use them. + +# Deeper collaboration with the US government + +The redeployment comes with a broader set of commitments tied to the June 2 Executive Order on Promoting Advanced Artificial Intelligence Innovation and Security. Anthropic's engagement spanned the Office of the National Cyber Director, the Office of Science and Technology Policy, the Treasury, the Department of Commerce including CAISI, and national security agencies. + +The commitments include: + +* Expanded early access for designated government partners to evaluate frontier models and safeguards before broad release +* Faster information sharing when significant jailbreaks or misuse patterns appear +* Dedicated teams and compute for joint research +* Work toward a shared, voluntary security and evaluation standard across frontier model providers + +Anthropic frames the goal as durable, transparent rules that give cyber defenders more certainty around access to powerful models. + +# Claude Fable 5 availability and pricing after redeployment + +Here is the part that affects your rollout plans. + +Claude Fable 5 is available starting Wednesday, July 1, to users globally on the Claude Platform, Claude.ai, Claude Code, and Claude Cowork. For Pro, Max, Team, and select Enterprise plans, Fable 5 is included for up to 50% of weekly usage limits through July 7, after which it is available via usage credits. Anthropic will re-enable access on AWS, Google Cloud, and Microsoft Foundry as quickly as possible. + +A note for Enterprise: standard Enterprise seats have no included Fable 5 allowance, so all usage is billed through usage credits, and Fable 5 will not work unless credits are enabled. Premium Enterprise seats include Fable 5 through July 7, drawing from each member's seat usage at no additional cost, after which enabling usage credits keeps it running. + +Access to Mythos 5 has been restored for a set of US organizations following the government's June 26 approval, and Anthropic says it is still coordinating to expand access across the broader Glasswing program. + +# What this means if you build on Appwrite + +The takeaway for developers is that Fable 5's long-horizon strengths, such as codebase-wide migrations and multi-step autonomous work, are back on the table, but the redeployment also comes with an important caveat. If a request is flagged as cybersecurity-adjacent, the classifier may route it to Opus 4.8 instead of continuing on Fable 5. + +That may prevent some requests from failing outright, but it can also create friction if an agent changes models mid-workflow. If you are building agentic apps, this is something to account for in testing, logs, and user experience. + +Beyond model behavior, agents still need the usual product infrastructure around them: authentication, stored state, file persistence, and server-side logic between steps. In other words, they still need a backend, and wiring one up by hand can slow down the path from prototype to product. + +If you want your Fable 5 agent to stand up that backend without manually assembling infrastructure, the [Appwrite plugin for Claude Code](https://appwrite.io/docs/tooling/claude-code) bundles the [Appwrite API MCP server](https://appwrite.io/docs/tooling/mcp), the Appwrite Docs MCP server, and SDK-specific agent skills into a single install. With the right project access and permissions, an agent can work directly with Appwrite APIs and docs to set up [Auth](https://appwrite.io/docs/products/auth), [Databases](https://appwrite.io/docs/products/databases), [Storage](https://appwrite.io/docs/products/storage), [Sites](https://appwrite.io/docs/products/sites), and [Functions](https://appwrite.io/docs/products/functions). + +# Build agentic apps on Appwrite + +Spin up the backend your next app needs in minutes. [Start for free on Appwrite Cloud](https://cloud.appwrite.io/), and let Appwrite handle Auth, Databases, Storage, Functions, Messaging, and Sites. Your Fable 5 agent builds the app, Appwrite runs the backend behind it, and you ship the product instead of wiring up the infrastructure. + +# Resources + +* [Appwrite MCP server docs](https://appwrite.io/docs/tooling/ai/mcp-servers/) +* [Start building on Appwrite Cloud](https://cloud.appwrite.io/) +* [Appwrite AI tooling](https://appwrite.io/docs/tooling/ai) +* [Appwrite integrations](https://appwrite.io/integrations) +* [Join the Appwrite Discord](https://appwrite.io/discord) \ No newline at end of file diff --git a/static/images/blog/claude-fable-5-returns-with-stronger-jailbreak-safeguards/cover.avif b/static/images/blog/claude-fable-5-returns-with-stronger-jailbreak-safeguards/cover.avif new file mode 100644 index 0000000000000000000000000000000000000000..cca659c1627e4d8f3769ca5499be59467ad22b23 GIT binary patch literal 5641 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 QAiz-G!8Pq&+3w!|0G(%3?f?J) literal 0 HcmV?d00001 From b0e55d4ee085aec8577aa6dca3fef6a3af4b038a Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Thu, 2 Jul 2026 12:20:09 +0530 Subject: [PATCH 58/61] Apply suggestions from code review Co-authored-by: Atharva Deosthale --- .../+page.markdoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/blog/post/claude-fable-5-returns-with-stronger-jailbreak-safeguards/+page.markdoc b/src/routes/blog/post/claude-fable-5-returns-with-stronger-jailbreak-safeguards/+page.markdoc index 38003da4f08..3f35928f596 100644 --- a/src/routes/blog/post/claude-fable-5-returns-with-stronger-jailbreak-safeguards/+page.markdoc +++ b/src/routes/blog/post/claude-fable-5-returns-with-stronger-jailbreak-safeguards/+page.markdoc @@ -123,8 +123,8 @@ Spin up the backend your next app needs in minutes. [Start for free on Appwrite # Resources -* [Appwrite MCP server docs](https://appwrite.io/docs/tooling/ai/mcp-servers/) +* [Appwrite MCP server docs](/docs/tooling/ai/mcp-servers/) * [Start building on Appwrite Cloud](https://cloud.appwrite.io/) -* [Appwrite AI tooling](https://appwrite.io/docs/tooling/ai) -* [Appwrite integrations](https://appwrite.io/integrations) +* [Appwrite AI tooling](/docs/tooling/ai) +* [Appwrite integrations](/integrations) * [Join the Appwrite Discord](https://appwrite.io/discord) \ No newline at end of file From 5268f5eca3df69fb15b5ad919e47df0876b8b73b Mon Sep 17 00:00:00 2001 From: Aishwari Pahwa Date: Thu, 2 Jul 2026 12:24:14 +0530 Subject: [PATCH 59/61] made changes to blog --- .../+page.markdoc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/routes/blog/post/best-vibe-coding-tools-for-beginners-in-2026/+page.markdoc b/src/routes/blog/post/best-vibe-coding-tools-for-beginners-in-2026/+page.markdoc index 7de45498bb0..0016600e738 100644 --- a/src/routes/blog/post/best-vibe-coding-tools-for-beginners-in-2026/+page.markdoc +++ b/src/routes/blog/post/best-vibe-coding-tools-for-beginners-in-2026/+page.markdoc @@ -1,7 +1,7 @@ --- layout: post title: Best vibe coding tools for beginners in 2026 -description: Compare the best vibe coding tools for beginners in 2026 and learn how to choose the right AI coding tool to build faster, avoid setup friction, and ship your app with Appwrite. +description: Compare the best vibe coding tools for beginners in 2026 and learn how to choose the right AI coding tool to build faster with Appwrite. date: 2026-05-25 cover: /images/blog/best-vibe-coding-tools-for-beginners-in-2026/cover.avif timeToRead: 5 @@ -47,7 +47,7 @@ With those filters in mind, here is the list. Claude Code is Anthropic's agentic coding tool that started in the terminal and now works across the terminal, IDE, desktop app, and browser. The terminal sounds intimidating, but the experience is closer to texting a senior engineer than writing shell commands. It reads your repo, makes changes, runs tests, and explains what it did in plain English. -Best for: beginners who want UI to be the major focus of their projects and prefer workflows like subagents to handle many tasks at once. +Best for: beginners who want UI to be the major focus of their projects and prefer workflows like subagents to handle many tasks at once. ## 2. Codex @@ -129,6 +129,8 @@ Vibe coding tools are great at scaffolding the app you can see. The part you can Appwrite is a backend platform developers can use once their projects need more than a quick prototype. A Cloud version that gets out of your way so you can ship. One platform for auth, database, storage, functions, messaging, and realtime, with SDKs that feel native in whatever framework your AI just spun up. +Recent releases have added [MongoDB support, Appwrite 1.9.0, realtime upgrades, and new AI tooling](https://dev.to/appwrite/april-product-update-mongodb-support-appwrite-190-realtime-upgrades-and-ai-tooling-1eg6), with [more landing every few weeks](https://dev.to/appwrite/may-product-update-presences-api-rust-runtime-7x-faster-storage-uploads-and-more-9h5). We post weekly roundups of product announcements, AI updates, and [developer insights](https://dev.to/appwrite/weekly-roundup-presences-api-git-deployment-triggers-and-ai-updates-58lj) on the [Appwrite blog](https://appwrite.io/blog) and across our developer channels, so follow along wherever you read. + Sign up for [Appwrite Cloud](https://cloud.appwrite.io/) or set up a self-hosted instance, and give your AI-built app a real backend for auth, data, storage, functions, messaging, and realtime. # Resources @@ -139,4 +141,4 @@ Sign up for [Appwrite Cloud](https://cloud.appwrite.io/) or set up a self-hosted * [Appwrite integrations](/integrations) * [Appwrite quick start guides](/docs/quick-starts) * [Appwrite on GitHub](https://github.com/appwrite/appwrite) -* [Join the Appwrite Discord](https://appwrite.io/discord) +* [Join the Appwrite Discord](https://appwrite.io/discord) \ No newline at end of file From 3571de2e2f23b375f7d86f068dbc54dfe54ce9ad Mon Sep 17 00:00:00 2001 From: Aishwari Pahwa Date: Thu, 2 Jul 2026 15:25:31 +0530 Subject: [PATCH 60/61] Update +page.markdoc --- .../+page.markdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/blog/post/best-vibe-coding-tools-for-beginners-in-2026/+page.markdoc b/src/routes/blog/post/best-vibe-coding-tools-for-beginners-in-2026/+page.markdoc index 0016600e738..4c6d0bd4c62 100644 --- a/src/routes/blog/post/best-vibe-coding-tools-for-beginners-in-2026/+page.markdoc +++ b/src/routes/blog/post/best-vibe-coding-tools-for-beginners-in-2026/+page.markdoc @@ -129,7 +129,7 @@ Vibe coding tools are great at scaffolding the app you can see. The part you can Appwrite is a backend platform developers can use once their projects need more than a quick prototype. A Cloud version that gets out of your way so you can ship. One platform for auth, database, storage, functions, messaging, and realtime, with SDKs that feel native in whatever framework your AI just spun up. -Recent releases have added [MongoDB support, Appwrite 1.9.0, realtime upgrades, and new AI tooling](https://dev.to/appwrite/april-product-update-mongodb-support-appwrite-190-realtime-upgrades-and-ai-tooling-1eg6), with [more landing every few weeks](https://dev.to/appwrite/may-product-update-presences-api-rust-runtime-7x-faster-storage-uploads-and-more-9h5). We post weekly roundups of product announcements, AI updates, and [developer insights](https://dev.to/appwrite/weekly-roundup-presences-api-git-deployment-triggers-and-ai-updates-58lj) on the [Appwrite blog](https://appwrite.io/blog) and across our developer channels, so follow along wherever you read. +Recent releases have added [MongoDB support, Appwrite 1.9.0, realtime upgrades, and new AI tooling](https://dev.to/appwrite/april-product-update-mongodb-support-appwrite-190-realtime-upgrades-and-ai-tooling-1eg6), with [more landing every few weeks](https://dev.to/appwrite/may-product-update-presences-api-rust-runtime-7x-faster-storage-uploads-and-more-9h5). We post weekly roundups of product announcements, AI updates, and [developer insights](https://dev.to/appwrite/weekly-roundup-presences-api-git-deployment-triggers-and-ai-updates-58lj) on the [Appwrite blog](https://appwrite.io/blog) and across our developer channels, so follow along wherever you read. Sign up for [Appwrite Cloud](https://cloud.appwrite.io/) or set up a self-hosted instance, and give your AI-built app a real backend for auth, data, storage, functions, messaging, and realtime. @@ -141,4 +141,4 @@ Sign up for [Appwrite Cloud](https://cloud.appwrite.io/) or set up a self-hosted * [Appwrite integrations](/integrations) * [Appwrite quick start guides](/docs/quick-starts) * [Appwrite on GitHub](https://github.com/appwrite/appwrite) -* [Join the Appwrite Discord](https://appwrite.io/discord) \ No newline at end of file +* [Join the Appwrite Discord](https://appwrite.io/discord) From 6048cadc3cd2bb657562fb4d2f0f03cef08b8361 Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:33:51 +0200 Subject: [PATCH 61/61] ci: write image tag to global.image.tag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The applications repo now sets the image once under `global.image` (generic chart 1.7.0 fallbacks); the bump writes the single canonical path `.global.image.tag` in default.yaml instead of per-alias keys. Merge AFTER appwrite-labs/assets-applications#29 — until then per-alias writes still override global, so deploys stay correct either way. Co-Authored-By: Claude Fable 5 --- .github/workflows/production.yml | 2 +- .github/workflows/staging.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index f36eda653bf..1aa5c129479 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -86,7 +86,7 @@ jobs: token: ${{ steps.app-token.outputs.token }} - name: Update image tag - run: yq -i '.website.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml + run: yq -i '.global.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml - name: Commit and push run: | diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index 3736ba9d148..9a6ba173d2a 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -89,7 +89,7 @@ jobs: token: ${{ steps.app-token.outputs.token }} - name: Update image tag - run: yq -i '.website.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml + run: yq -i '.global.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml - name: Commit and push run: |