@appwrite.io/react
v0.1.0-rc.3
Published
[](https://appwrite.io/discord)
Keywords
Readme
Appwrite React SDK
Appwrite is an open-source backend as a service that abstracts common application features behind simple APIs. The Appwrite React SDK provides React hooks and framework adapters for Appwrite authentication in client-rendered and server-rendered React apps.

Features
- React provider and hooks for sign-up, sign-in, sign-out, OAuth, and current user state
- Client-side auth for Vite and other non-SSR React apps
- SSR auth handlers for Next.js and TanStack Start
- Server helpers for reading the current user/session from HTTP-only cookies
- Server-context session clients and admin clients
Installation
For client-rendered React apps:
pnpm add @appwrite.io/react appwrite @tanstack/react-queryFor SSR apps that use the server handlers or admin client, also install node-appwrite:
pnpm add @appwrite.io/react appwrite node-appwrite @tanstack/react-queryFramework packages such as next, @tanstack/react-start, react, and react-dom should come from your app scaffold.
Non-SSR React Apps
Use this setup for Vite or any app where auth is handled directly in the browser.
import { AppwriteProvider } from "@appwrite.io/react";
export function Root() {
return (
<AppwriteProvider
endpoint={import.meta.env.VITE_APPWRITE_ENDPOINT}
projectId={import.meta.env.VITE_APPWRITE_PROJECT_ID}
>
<App />
</AppwriteProvider>
);
}Then, for authentication:
import { useAuth } from "@appwrite.io/react";
export function AuthPanel() {
const { user, isLoading, signIn, signUp, signOut } = useAuth();
if (isLoading) return <p>Loading...</p>;
if (!user) {
return (
<>
<button
onClick={() =>
signIn.emailPassword({
email: "[email protected]",
password: "password123",
})
}
>
Sign in
</button>
<button
onClick={() =>
signUp.emailPassword({
email: "[email protected]",
password: "password123",
name: "Jane Doe",
})
}
>
Sign up
</button>
</>
);
}
return (
<>
<p>Signed in as {user.email}</p>
<button onClick={() => signOut.signOut()}>Sign out</button>
</>
);
}Next.js App Router SSR
Set public Appwrite values and keep only the API key private:
NEXT_PUBLIC_APPWRITE_ENDPOINT=https://fra.cloud.appwrite.io/v1
NEXT_PUBLIC_APPWRITE_PROJECT_ID=PROJECT_ID
APPWRITE_API_KEY=SERVER_ONLY_API_KEYCreate the Appwrite auth handler route:
// 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",
});Pass the server session into the client provider:
// app/providers.tsx
"use client";
import { AppwriteProvider } from "@appwrite.io/react";
export function Providers({
session,
children,
}: {
session?: string | null;
children: React.ReactNode;
}) {
return (
<AppwriteProvider
endpoint={process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}
projectId={process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!}
ssr={{ session, basePath: "/api/appwrite" }}
>
{children}
</AppwriteProvider>
);
}// app/layout.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,
}: {
children: React.ReactNode;
}) {
const helpers = createNextServerHelpers(appwrite);
const session = await helpers.readSessionCookie();
return (
<html lang="en">
<body>
<Providers session={session}>{children}</Providers>
</body>
</html>
);
}Read SSR auth state and create server-context clients:
// app/page.tsx
import { createNextServerHelpers } from "@appwrite.io/react/server/next";
const appwrite = {
endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!,
projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
apiKey: process.env.APPWRITE_API_KEY!,
};
export default async function Page() {
const helpers = createNextServerHelpers(appwrite);
const user = await helpers.getLoggedInUser();
const sessionClient = await helpers.createSessionClient();
const adminClient = helpers.createAdminClient();
const users = await adminClient.users.list({ total: false });
return (
<main>
<p>SSR user: {user?.email ?? "signed out"}</p>
<p>Session client: {sessionClient ? "available" : "none"}</p>
<p>Admin users loaded: {users.users.length}</p>
</main>
);
}In client components, use the same hooks. Refresh the router after auth mutations when server-rendered state should update.
// app/auth-panel.tsx
"use client";
import { useAuth } from "@appwrite.io/react";
import { useRouter } from "next/navigation";
export function AuthPanel() {
const { user, isLoading, signIn, signOut } = useAuth();
const router = useRouter();
if (isLoading) return <p>Loading...</p>;
if (!user) {
return (
<button
onClick={() =>
signIn.emailPassword({
email: "[email protected]",
password: "password123",
onSuccess: () => router.refresh(),
})
}
>
Sign in
</button>
);
}
return (
<button
onClick={() => signOut.signOut({ onSuccess: () => router.refresh() })}
>
Sign out
</button>
);
}TanStack Start SSR
Set public Appwrite values and keep only the API key private:
VITE_APPWRITE_ENDPOINT=https://fra.cloud.appwrite.io/v1
VITE_APPWRITE_PROJECT_ID=PROJECT_ID
APPWRITE_API_KEY=SERVER_ONLY_API_KEYCreate the Appwrite auth handler route:
// 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",
}),
},
});Read SSR auth state in a server function and pass the session into the provider:
// src/routes/index.tsx
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 appwrite = {
endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT,
projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID,
apiKey: process.env.APPWRITE_API_KEY!,
};
const helpers = createTanStackServerHelpers(appwrite);
const user = await helpers.getLoggedInUser();
const sessionClient = await helpers.createSessionClient();
const adminClient = helpers.createAdminClient();
const users = await adminClient.users.list({ total: false });
return {
session: helpers.readSessionCookie() ?? null,
user,
hasSessionClient: Boolean(sessionClient),
adminUserCount: users.users.length,
};
});
export const Route = createFileRoute("/")({
loader: () => getAuthSnapshot(),
component: Page,
});
function Page() {
const { session, user, hasSessionClient, adminUserCount } = Route.useLoaderData();
return (
<AppwriteProvider
endpoint={import.meta.env.VITE_APPWRITE_ENDPOINT}
projectId={import.meta.env.VITE_APPWRITE_PROJECT_ID}
ssr={{ session, basePath: "/api/appwrite" }}
>
<main>
<p>SSR user: {user?.email ?? "signed out"}</p>
<p>Session client: {hasSessionClient ? "available" : "none"}</p>
<p>Admin users loaded: {adminUserCount}</p>
<AuthPanel />
</main>
</AppwriteProvider>
);
}
function AuthPanel() {
const { user, isLoading, signIn, signOut } = useAuth();
const router = useRouter();
if (isLoading) return <p>Loading...</p>;
if (!user) {
return (
<button
onClick={() =>
signIn.emailPassword({
email: "[email protected]",
password: "password123",
onSuccess: () => router.invalidate(),
})
}
>
Sign in
</button>
);
}
return (
<button
onClick={() => signOut.signOut({ onSuccess: () => router.invalidate() })}
>
Sign out
</button>
);
}API Overview
Client entrypoint:
import {
AppwriteProvider,
OAuthProvider,
useAuth,
useSignIn,
useSignOut,
useSignUp,
useUser,
} from "@appwrite.io/react";Server entrypoints:
import { createAppwriteHandlers as createNextAppwriteHandlers } from "@appwrite.io/react/handlers/next";
import { createAppwriteHandlers as createTanStackAppwriteHandlers } from "@appwrite.io/react/handlers/tanstack";
import {
createAdminClient,
createSessionClient,
} from "@appwrite.io/react/server";
import { createNextServerHelpers } from "@appwrite.io/react/server/next";
import { createTanStackServerHelpers } from "@appwrite.io/react/server/tanstack";Do not import server entrypoints from client components or browser-only code.
Learn More
License
Please see the MIT license file for more information.
