> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.recursiv.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.recursiv.io/_mcp/server.

# App Recipes

Recipes for the backend an app needs: data, files, email, auth and shipping to a URL. Recursiv gives you all of it from one SDK, so you never wire up separate services. Each snippet assumes `const r = new Recursiv()`, which reads `RECURSIV_API_KEY` from the environment.

### Provision a database

Call `ensure` on every deploy. It creates the Postgres database the first time and returns the existing one after that, so it is safe to run repeatedly.

```typescript
const { data: db } = await r.databases.ensure({
  project_id: 'proj_123',
  name: 'main',
});

console.log(db.name, db.status);
```

### Query the database

Run SQL straight against a project's database and read the rows back.

```typescript
const { data } = await r.databases.query({
  project_id: 'proj_123',
  sql: 'SELECT id, email FROM users ORDER BY created_at DESC LIMIT 10',
});

for (const row of data.rows) {
  console.log(row.id, row.email);
}
```

### Upload a file

Storage uploads are two steps: get a presigned URL, then PUT the bytes directly to it. `ensureBucket` is idempotent.

```typescript
import fs from 'node:fs';

await r.storage.ensureBucket({ project_id: 'proj_123', name: 'uploads' });

const { data: { url } } = await r.storage.getUploadUrl({
  project_id: 'proj_123',
  bucket_name: 'uploads',
  key: 'avatars/user_42.png',
  content_type: 'image/png',
});

await fetch(url, {
  method: 'PUT',
  headers: { 'Content-Type': 'image/png' },
  body: await fs.promises.readFile('./avatar.png'),
});
```

### Share a file with a download link

Generate a presigned download URL to hand to a browser or client.

```typescript
const { data: { url } } = await r.storage.getDownloadUrl({
  project_id: 'proj_123',
  bucket_name: 'uploads',
  key: 'avatars/user_42.png',
});

console.log('Download:', url); // time-limited, no credentials needed
```

### Send an email

Send a transactional email. With a BYOK Resend key on the org, it sends from your own domain.

```typescript
const { data: result } = await r.email.send({
  to: 'customer@example.com',
  subject: 'Your order shipped',
  html: '<h1>Order #1234</h1><p>On its way.</p>',
});

console.log(result.id, result.status);
```

### Add email and password auth

Sign a user up and mint an API key for them in one call. Ideal for mobile, where cookies do not persist. Bind the key to the project so users become app members.

```typescript
const anon = new Recursiv({ anonymous: true });

const { apiKey, user } = await anon.auth.signUpAndCreateKey(
  { email: 'new@example.com', password: 'a-strong-passphrase-12', name: 'New User' },
  { name: 'mobile-app', scopes: ['posts:read', 'posts:write'], projectId: 'proj_123' },
);

const userClient = new Recursiv({ apiKey });
```

### Add passwordless (OTP) auth

Email a one-time code, then verify it to sign in. Auto-creates the user if they are new.

```typescript
const anon = new Recursiv({ anonymous: true });

await anon.auth.sendOtp({ email: 'user@example.com' });

// ...user enters the code from their inbox
const { apiKey } = await anon.auth.verifyOtpAndCreateKey(
  { email: 'user@example.com', otp: '123456' },
  { name: 'web-session', scopes: ['posts:read'], projectId: 'proj_123' },
);
```

### Scaffold a new app from a template

Create a deployable Next.js or Expo repo server-side. No local `gh`, git or GitHub account required.

```typescript
const { data: repo } = await r.github.createFromTemplate({
  template: 'nextjs', // or 'expo'
  name: 'my-app',
});

console.log(repo.repo_url);
```

### Deploy to a live URL

Link a repo to a project, then deploy. The deployment URL is returned once it is live.

```typescript
const { data: project } = await r.projects.create({
  organization_id: 'org_123',
  name: 'my-app',
  repo_url: repo.repo_url,
});

const { data: deployment } = await r.projects.deploy(project.id, {
  branch: 'main',
  type: 'production',
});

console.log(deployment.status, deployment.deployment_url);
```

### Tail deployment logs

Read build and runtime logs for a deployment to debug a failed ship.

```typescript
const { data: logs } = await r.projects.deploymentLogs(project.id, deployment.id);
console.log(logs.logs);
```