> Set up the Pylo SDK in an Expo or React Native app, with tokens in the device keychain

# Expo Quickstart

The Expo SDK (`@pylo/expo`) is everything [`@pylo/react`](/getting-started/quickstart-react)
provides, with the device keychain wired up as the token store and app focus wired up to React
Query.

## Install

```bash
# expo
npx expo install @pylo/expo @tanstack/react-query expo-secure-store
```

## 1. Generate types

Create an API token in **Settings > API Tokens** in the admin panel (see
[API Tokens](/authentication/api-tokens)) and put it in `.env`.

```bash filename=".env"
PYLO_API_KEY=your-api-token-here
```

```typescript filename="pylo.config.ts"
import { defineConfig } from '@pylo/expo/codegen';

export default defineConfig({
  apiKey: process.env.PYLO_API_KEY!,
  output: '.pylo', // optional, defaults to '.pylo'
});
```

```bash
# expo
npx pylo generate
```

The generated `index.ts` registers the schema on `@pylo/expo`, so the `PyloSelect` and `PyloResult`
helpers are typed with no `declare module` step.

> **Keep the token out of your bundle**
> Only `pylo generate` reads `PYLO_API_KEY`, and only at build time. Expo inlines an environment
> variable into the app only when its name starts with `EXPO_PUBLIC_`, so an unprefixed name stays
> out of the bundle.

## 2. Add the provider

Import `PyloProvider` from `@pylo/expo` and pass no `storage`: it defaults to SecureStore.

```tsx filename="App.tsx"
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { PyloProvider } from '@pylo/expo';
import { Root } from './Root';

const queryClient = new QueryClient();

export default function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <PyloProvider appId={process.env.EXPO_PUBLIC_PYLO_APP_ID}>
        <Root />
      </PyloProvider>
    </QueryClientProvider>
  );
}
```

`appId` scopes the session to one app. Find your app id in **Settings > Apps** in the admin panel.

## 3. Use the hooks

`usePyloAuth`, `createPyloHooks`, `usePyloClient` and the rest are re-exported from `@pylo/expo`
unchanged. Follow the [React Quickstart](/getting-started/quickstart-react) from here.

```typescript filename="lib/pylo.ts"
import { createPyloHooks } from '@pylo/expo';
import type { PyloSchema } from '../.pylo';

export const pylo = createPyloHooks<PyloSchema>();
```

## Token storage

SecureStore is backed by the OS keychain, so tokens are encrypted at rest and a native app has no
XSS surface to leak them through. Reads are asynchronous, which is why `usePyloAuth` reports
`isLoading` until the stored session has been read.

## Uploading files

React Native has no `File` for a local file. Pass the reference its pickers return, and the platform
streams it from disk.

```tsx
const { startUpload } = pylo.usePyloUpload({ entityRelationPath: 'contact.avatar' });

await startUpload({ uri: asset.uri, name: asset.fileName, type: asset.mimeType });
```

Such a reference carries no byte length, so progress across a batch weights each file equally rather
than by size. See [Uploading & Downloading](/files/sdk) for the rest of the upload API.

## Refetching when the app returns to the foreground

TanStack Query decides focus from a browser event React Native does not have, so without wiring,
queries never refetch when your app foregrounds. `PyloProvider` does this for you.

TanStack's focus manager is global, so it applies to every query in your app, not only Pylo's. That
is what TanStack's own React Native guide recommends. If you already wire it up yourself, turn ours
off:

```tsx
<PyloProvider refetchOnAppFocus={false}>
```

Network state is a separate matter and stays opt-in, because it needs a community package. See the
[TanStack Query React Native guide](https://tanstack.com/query/latest/docs/framework/react/react-native)
for that half.

Next: [Querying](/data/querying)
