# Convex

> A React Native starter with BNA UI components and a Convex backend — real-time data, with or without Google, Apple, password and email OTP authentication.

**BNA UI** — a React Native / Expo component library.
These components render through `react-native`, not the DOM: there are no HTML
elements, no Tailwind classes and no Radix primitives. Source is copied into your
project and imported through `@/components/ui/*`, `@/components/charts/*`,
`@/hooks/*` and `@/theme/*`. Colours come from the `useColor` hook rather than
hardcoded hex; sizing tokens (`HEIGHT`, `FONT_SIZE`, `BORDER_RADIUS`, `CORNERS`)
come from `@/theme/globals`.

- Docs: https://ui.ahmedbna.com/docs/convex
- Markdown: https://ui.ahmedbna.com/docs/convex.md

---

[Convex](https://convex.dev) is a real-time backend. You write queries and
mutations as TypeScript functions, and every client subscribed to a query
re-renders when its data changes — no refetching, no cache invalidation.

BNA UI ships two Convex scaffolds: one with a backend and no sign-in, one with
[`@convex-dev/auth`](https://labs.convex.dev/auth) and the sign-in screens
already built.

[Expo + Convex](/docs/installation/convex) — A schema and a live query. No authentication.

[Expo + Convex + Auth](/docs/installation/convex-auth) — Google, Apple, password and email OTP sign-in, pre-wired.

This section covers the schema, authentication, realtime, storage, actions and
deployment for both scaffolds, plus provider setup for
[Google](/docs/convex/google), [Apple](/docs/convex/apple) and
[Resend](/docs/convex/resend).

## The auth starter

Built around the same principles as the rest of BNA UI:

- **Open Code:** the authentication screens and the Convex functions are copied
  into your project, not imported from a package.
- **Mobile-First:** flows designed for React Native, with tokens in the platform
  keychain.
- **Cross-Platform:** iOS, Android and web.
- **Real-Time:** every query is a live subscription.

### Sign-in methods

| Method           | Provider                                  | Ships with a button  |
| ---------------- | ----------------------------------------- | -------------------- |
| Anonymous        | `@convex-dev/auth` `Anonymous`            | Yes                  |
| Email + password | `@convex-dev/auth` `Password`, with reset | Yes                  |
| Email OTP        | Resend                                    | Yes                  |
| Google           | `@auth/core` Google                       | Yes                  |
| Apple            | `@auth/core` Apple                        | Yes                  |
| GitHub           | `@auth/core` GitHub                       | No — configured only |

GitHub is set up in `convex/auth.ts` but the sign-in screen has no button for
it. Model one on `components/auth/google.tsx` if you want it.

### What lands in your project

```
app/_layout.tsx           ConvexAuthProvider, switching on auth state
components/auth/
├── auth.tsx              The sign-in screen: Password / OAuth / OTP tabs
├── password.tsx          Sign in, sign up, forgot and reset password
├── email-otp.tsx         Passwordless email codes
├── google.tsx            Google sign-in button
├── apple.tsx             Apple sign-in button
└── singout.tsx           Sign-out button, used in the settings tab
convex/
├── auth.ts               Providers, password rules, redirect allow-list
├── auth.config.ts        JWT issuer
├── schema.ts             authTables + a users table
├── users.ts              User queries and mutations
├── http.ts               Mounts the auth HTTP routes
├── resendOTP.ts          Email OTP delivery
├── passwordReset.ts      Password-reset codes
└── resendPasswordOTP.ts
```

The root layout renders a spinner while the session resolves, the sign-in screen
when signed out, and your tabs when signed in:

```tsx title="app/_layout.tsx"
<ConvexAuthProvider client={convex} storage={secureStorage}>
  <AuthLoading>
    <Spinner size='lg' variant='circle' />
  </AuthLoading>
  <Unauthenticated>
    <Auth />
  </Unauthenticated>
  <Authenticated>
    <Stack>{/* your app */}</Stack>
  </Authenticated>
</ConvexAuthProvider>
```

`storage` is `expo-secure-store` on iOS and Android — the Keychain and the
Keystore respectively — and the platform default on web.

### Reading the signed-in user

```ts title="convex/users.ts"
export const get = query({
  handler: async (ctx) => {
    const authId = await getAuthUserId(ctx);

    if (!authId) {
      throw new Error('Not authenticated');
    }

    return await ctx.db.get(authId);
  },
});
```

### Password rules

`convex/auth.ts` requires at least 8 characters with one digit, one lowercase
and one uppercase letter. Edit `validatePasswordRequirements` to change it — it
throws, and the message surfaces in the sign-up form.

## Environment

| Variable                 | Where it lives    | Set by                | Used for                              |
| ------------------------ | ----------------- | --------------------- | ------------------------------------- |
| `EXPO_PUBLIC_CONVEX_URL` | `.env.local`      | `npx convex dev`      | Building the client                   |
| `EXPO_URL`               | Convex deployment | `bna-ui convex`       | Allow-listing your app scheme         |
| `SITE_URL`               | Convex deployment | `bna-ui convex`       | Allow-listing the web redirect target |
| `AUTH_RESEND_KEY`        | Convex deployment | you                   | Email OTP and password reset          |
| `AUTH_GOOGLE_ID/SECRET`  | Convex deployment | you                   | Google sign-in                        |
| `AUTH_APPLE_ID/SECRET`   | Convex deployment | you                   | Apple sign-in                         |
| `CONVEX_SITE_URL`        | Convex deployment | Convex, automatically | The JWT issuer                        |

Deployment variables are set with `npx convex env set NAME value` and listed
with `npx convex env list`. They are not in `.env.local`, because server-side
functions read them.

The full walkthrough, including production, is in the [auth installation
guide](/docs/installation/convex-auth).

## Guides

- [Database and schema](/docs/convex/database) — defineTable, indexes, and how
  authorization replaces RLS
- [Authentication](/docs/convex/auth) — session storage, route guards, OAuth,
  and the redirect allow-list
- [Google](/docs/convex/google) · [Apple](/docs/convex/apple) ·
  [Resend](/docs/convex/resend)
- [Storage](/docs/convex/storage) · [Realtime](/docs/convex/realtime) ·
  [Actions](/docs/convex/actions)
- [Deployment](/docs/convex/deployment) — EAS, CI, and dev vs. prod deployments
- [Troubleshooting](/docs/convex/troubleshooting) — and a Supabase → Convex
  migration guide

## Learn more

- [Convex documentation](https://docs.convex.dev)
- [Convex Auth documentation](https://labs.convex.dev/auth)
- [Report an issue](https://github.com/ahmedbna/ui/issues)
