Agent skill

Expo API Routes

by adrianhajdin in adrianhajdin/react-native-lingua

Guidelines for creating API routes in Expo Router with EAS Hosting

MITAuto-check: notesMobile

Install Expo API Routes

skills CLI
$ npx skills add adrianhajdin/react-native-lingua --skill expo-api-routes -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install adrianhajdin/react-native-lingua expo-api-routes --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/adrianhajdin/react-native-lingua.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/expo-api-routes .claude/skills/expo-api-routes && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
expo-api-routes
GitHub stars
152
Used in
6 other repos
Token cost
~2.2k tokens
SKILL.md length
423 words
Files
1
Skills in repo
7
Repo updated
First seen
Licence
MIT

At a glance

Guidelines for creating API routes in Expo Router with EAS Hosting

  • Tasks that involve Cross-platform mobile apps
  • SKILL.md covers When to Use API Routes, When NOT to Use API Routes, File Structure and Basic API Route, plus 12 more sections
  • Calls eas, curl and npx; reaches api.openai.com and api.weather.com; needs OPENAI_API_KEY and TURSO_AUTH_TOKEN

What it does

Expo API Routes is an agent skill from adrianhajdin/react-native-lingua. Guidelines for creating API routes in Expo Router with EAS Hosting

Its SKILL.md is about 2.2k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Mobile, covering Cross-platform mobile apps. It works with Expo and Cloudflare Workers. The repository describes itself as: React Native Duolingo clone with a real-time AI voice teacher. Built with Expo, Stream Voice Agents, Clerk auth, and NativeWind for a complete, interactive mobile learning… The licence is MIT.

When your agent uses it

  • Tasks that involve Cross-platform mobile apps

Example prompts

  • “Use the expo-api-routes skill to guideline for creating API routes in Expo Router with EAS Hosting”
  • “/expo-api-routes”

Requirements

  • Node.js
  • A credential in OPENAI_API_KEY
  • A credential in TURSO_AUTH_TOKEN

What it can do on your machine

Read from SKILL.md and the folder at commit 7ddc202. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • eas
    • curl
    • npx
    • npm

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • api.openai.com
    • api.weather.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names these keys or tokens, usually read from environment variables:

    • OPENAI_API_KEY
    • TURSO_AUTH_TOKEN
    • WEATHER_API_KEY

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Expo API Routes loads about 2.2k tokens when it runs. Until then it costs about 21 tokens; SKILL.md has 423 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~21
When it runs · the whole SKILL.md, loaded when a task matches
~2.2k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check: notes

The automated check noted patterns worth knowing about, such as sudo or a known installer.

  • NoteMentions a .env fileSKILL.md:158
    - **Local**: Create `.env` file (never commit)

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from adrianhajdin/react-native-lingua at commit 7ddc202, republished under its MIT licence (© adrianhajdin). 423 words, ~2,163 tokens.

Download SKILL.mdSave it as .claude/skills/expo-api-routes/SKILL.md (or your agent's skills folder).
name
expo-api-routes
description
Guidelines for creating API routes in Expo Router with EAS Hosting
version
1.0.0
license
MIT

When to Use API Routes

Use API routes when you need:

  • Server-side secrets — API keys, database credentials, or tokens that must never reach the client
  • Database operations — Direct database queries that shouldn't be exposed
  • Third-party API proxies — Hide API keys when calling external services (OpenAI, Stripe, etc.)
  • Server-side validation — Validate data before database writes
  • Webhook endpoints — Receive callbacks from services like Stripe or GitHub
  • Rate limiting — Control access at the server level
  • Heavy computation — Offload processing that would be slow on mobile

When NOT to Use API Routes

Avoid API routes when:

  • Data is already public — Use direct fetch to public APIs instead
  • No secrets required — Static data or client-safe operations
  • Real-time updates needed — Use WebSockets or services like Supabase Realtime
  • Simple CRUD — Consider Firebase, Supabase, or Convex for managed backends
  • File uploads — Use direct-to-storage uploads (S3 presigned URLs, Cloudflare R2)
  • Authentication only — Use Clerk, Auth0, or Firebase Auth instead

File Structure

API routes live in the app directory with +api.ts suffix:

app/
  api/
    hello+api.ts          → GET /api/hello
    users+api.ts          → /api/users
    users/[id]+api.ts     → /api/users/:id
  (tabs)/
    index.tsx

Basic API Route

ts
// app/api/hello+api.ts
export function GET(request: Request) {
  return Response.json({ message: "Hello from Expo!" });
}

HTTP Methods

Export named functions for each HTTP method:

ts
// app/api/items+api.ts
export function GET(request: Request) {
  return Response.json({ items: [] });
}

export async function POST(request: Request) {
  const body = await request.json();
  return Response.json({ created: body }, { status: 201 });
}

export async function PUT(request: Request) {
  const body = await request.json();
  return Response.json({ updated: body });
}

export async function DELETE(request: Request) {
  return new Response(null, { status: 204 });
}

Dynamic Routes

ts
// app/api/users/[id]+api.ts
export function GET(request: Request, { id }: { id: string }) {
  return Response.json({ userId: id });
}

Request Handling

Query Parameters
ts
export function GET(request: Request) {
  const url = new URL(request.url);
  const page = url.searchParams.get("page") ?? "1";
  const limit = url.searchParams.get("limit") ?? "10";

  return Response.json({ page, limit });
}
Headers
ts
export function GET(request: Request) {
  const auth = request.headers.get("Authorization");

  if (!auth) {
    return Response.json({ error: "Unauthorized" }, { status: 401 });
  }

  return Response.json({ authenticated: true });
}
JSON Body
ts
export async function POST(request: Request) {
  const { email, password } = await request.json();

  if (!email || !password) {
    return Response.json({ error: "Missing fields" }, { status: 400 });
  }

  return Response.json({ success: true });
}

Environment Variables

Use process.env for server-side secrets:

ts
// app/api/ai+api.ts
export async function POST(request: Request) {
  const { prompt } = await request.json();

  const response = await fetch("https://api.openai.com/v1/chat/completions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
    },
    body: JSON.stringify({
      model: "gpt-4",
      messages: [{ role: "user", content: prompt }],
    }),
  });

  const data = await response.json();
  return Response.json(data);
}

Set environment variables:

  • Local: Create .env file (never commit)
  • EAS Hosting: Use eas env:create or Expo dashboard

CORS Headers

Add CORS for web clients:

ts
const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type, Authorization",
};

export function OPTIONS() {
  return new Response(null, { headers: corsHeaders });
}

export function GET() {
  return Response.json({ data: "value" }, { headers: corsHeaders });
}

Error Handling

ts
export async function POST(request: Request) {
  try {
    const body = await request.json();
    // Process...
    return Response.json({ success: true });
  } catch (error) {
    console.error("API error:", error);
    return Response.json({ error: "Internal server error" }, { status: 500 });
  }
}

Testing Locally

Start the development server with API routes:

bash
npx expo serve

This starts a local server at http://localhost:8081 with full API route support.

Test with curl:

bash
curl http://localhost:8081/api/hello
curl -X POST http://localhost:8081/api/users -H "Content-Type: application/json" -d '{"name":"Test"}'

Deployment to EAS Hosting

Prerequisites
bash
npm install -g eas-cli
eas login
Deploy
bash
eas deploy

This builds and deploys your API routes to EAS Hosting (Cloudflare Workers).

Show full SKILL.md (165 more words)Show less
Environment Variables for Production
bash
# Create a secret
eas env:create --name OPENAI_API_KEY --value sk-xxx --environment production

# Or use the Expo dashboard
Custom Domain

Configure in eas.json or Expo dashboard.

EAS Hosting Runtime (Cloudflare Workers)

API routes run on Cloudflare Workers. Key limitations:

Missing/Limited APIs
  • No Node.js filesystem — fs module unavailable
  • No native Node modules — Use Web APIs or polyfills
  • Limited execution time — 30 second timeout for CPU-intensive tasks
  • No persistent connections — WebSockets require Durable Objects
  • fetch is available — Use standard fetch for HTTP requests
Use Web APIs Instead
ts
// Use Web Crypto instead of Node crypto
const hash = await crypto.subtle.digest(
  "SHA-256",
  new TextEncoder().encode("data")
);

// Use fetch instead of node-fetch
const response = await fetch("https://api.example.com");

// Use Response/Request (already available)
return new Response(JSON.stringify(data), {
  headers: { "Content-Type": "application/json" },
});
Database Options

Since filesystem is unavailable, use cloud databases:

  • Cloudflare D1 — SQLite at the edge
  • Turso — Distributed SQLite
  • PlanetScale — Serverless MySQL
  • Supabase — Postgres with REST API
  • Neon — Serverless Postgres

Example with Turso:

ts
// app/api/users+api.ts
import { createClient } from "@libsql/client/web";

const db = createClient({
  url: process.env.TURSO_URL!,
  authToken: process.env.TURSO_AUTH_TOKEN!,
});

export async function GET() {
  const result = await db.execute("SELECT * FROM users");
  return Response.json(result.rows);
}

Calling API Routes from Client

ts
// From React Native components
const response = await fetch("/api/hello");
const data = await response.json();

// With body
const response = await fetch("/api/users", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "John" }),
});

Common Patterns

Authentication Middleware
ts
// utils/auth.ts
export async function requireAuth(request: Request) {
  const token = request.headers.get("Authorization")?.replace("Bearer ", "");

  if (!token) {
    throw new Response(JSON.stringify({ error: "Unauthorized" }), {
      status: 401,
      headers: { "Content-Type": "application/json" },
    });
  }

  // Verify token...
  return { userId: "123" };
}

// app/api/protected+api.ts
import { requireAuth } from "../../utils/auth";

export async function GET(request: Request) {
  const { userId } = await requireAuth(request);
  return Response.json({ userId });
}
Proxy External API
ts
// app/api/weather+api.ts
export async function GET(request: Request) {
  const url = new URL(request.url);
  const city = url.searchParams.get("city");

  const response = await fetch(
    `https://api.weather.com/v1/current?city=${city}&key=${process.env.WEATHER_API_KEY}`
  );

  return Response.json(await response.json());
}

Rules

  • NEVER expose API keys or secrets in client code
  • ALWAYS validate and sanitize user input
  • Use proper HTTP status codes (200, 201, 400, 401, 404, 500)
  • Handle errors gracefully with try/catch
  • Keep API routes focused — one responsibility per endpoint
  • Use TypeScript for type safety
  • Log errors server-side for debugging

© adrianhajdin, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .agents/skills/expo-api-routes of adrianhajdin/react-native-lingua.

Open the folder on GitHubat commit 7ddc202

Used in 6 other repositories

We found 21 copies of this SKILL.md (exact, near-identical or edited) in other folders, from 6 other GitHub owners. This page covers the copy in adrianhajdin/react-native-lingua, which our catalogue first saw on October 7, 2026.

Compare with similar skills

Expo API Routes next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Expo API Routes compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Expo API Routes this skilladrianhajdin/react-native-lingua1526 repos~2.2kAutomated safety check: NotesMIT
Eas Hostingexpo/skills2.7k2 repos~2.9kAutomated safety check: NotesMIT
React Native Best Practicesvercel-labs/openreview1.7k17 repos~1.1kAutomated safety check: PassMIT
Expo Cicd WorkflowsCherryHQ/cherry-studio-app4k6 repos~870Automated safety check: PassMIT
Expo Modulebbplayer-app/BBPlayer1.2k3 repos~1.4kAutomated safety check: PassMIT
Appllama App Design SkillAppllama/appllama-skills2.5k1 repos~5kAutomated safety check: PassMIT

Similar skills

  • Eas Hosting

    expo/skills

    Official

    Deploy Expo websites and Expo Router API routes to EAS Hosting - export the web bundle, run eas deploy for production and PR preview URLs, manage environment secrets and custom domains, and work…

    2.7k GitHub starsUsed in 2 repos~2.9k tokens
    MobileAuto-check: notes
  • React Native Best Practices

    vercel-labs/openreview

    Official

    A prioritized rule set for React Native and Expo apps covering list performance, animation, navigation, UI patterns, state, rendering, monorepos and configuration.

    1.7k GitHub starsUsed in 17 repos~1.1k tokens
    MobileAuto-check passed
  • Expo Cicd Workflows

    CherryHQ/cherry-studio-app

    Helps understand and write EAS workflow YAML files for Expo projects.

    4k GitHub starsUsed in 6 repos~870 tokens
    MobileAuto-check passed
  • Expo Module

    bbplayer-app/BBPlayer

    Guide for creating and writing Expo native modules and views using the Expo Modules API (Swift, Kotlin, TypeScript).

    1.2k GitHub starsUsed in 3 repos~1.4k tokens
    MobileAuto-check passed
  • Appllama App Design Skill

    Appllama/appllama-skills

    Build native-feeling, benchmark-quality mobile app screens (Expo / React Native).

    2.5k GitHub starsUsed in 1 repo~5k tokens
    MobileAuto-check passed
  • Building Native UI

    CherryHQ/cherry-studio-app

    Complete guide for building beautiful apps with Expo Router.

    4k GitHub starsUsed in 8 repos~2.6k tokens
    MobileAuto-check passed

More from adrianhajdin/react-native-lingua

  • Clerk Expo Patterns

    adrianhajdin/react-native-lingua

    Expo / React Native patterns with Clerk — SecureStore token cache, OAuth deep linking, useAuth in native, Expo Router protected routes, push notifications with user context.

    152 GitHub stars~1.2k tokensUpdated 4 mo ago
    Auto-check passed
  • Stream React Native

    adrianhajdin/react-native-lingua

    Create, build, and integrate Stream Chat React Native apps in React Native Community CLI and Expo.

    152 GitHub stars~2.8k tokensUpdated 4 mo ago
    Auto-check passed
  • Stream Builder

    adrianhajdin/react-native-lingua

    Build a new app or add Stream products (Chat, Video, Feeds, Moderation) to an existing app.

    152 GitHub stars~5.4k tokensUpdated 4 mo ago
    Auto-check: notes
  • Stream CLI

    adrianhajdin/react-native-lingua

    Query Stream data and run CLI operations against Chat, Video, Feeds, and Moderation: list channels, list calls, show flagged messages, find users, query any Stream resource.

    152 GitHub stars~1.6k tokensUpdated 4 mo ago
    Auto-check: notes
  • Stream Docs

    adrianhajdin/react-native-lingua

    Search live Stream SDK documentation for Chat, Video, Feeds, and Moderation.

    152 GitHub stars~6.6k tokensUpdated 4 mo ago
    Auto-check passed
  • Stream

    adrianhajdin/react-native-lingua

    Stream router for Chat, Video, Feeds, and Moderation. An agent skill from adrianhajdin/react-native-lingua.

    152 GitHub stars~1.9k tokensUpdated 4 mo ago
    Auto-check passed

Categories

Questions about Expo API Routes

What does Expo API Routes do?

Guidelines for creating API routes in Expo Router with EAS Hosting. Expo API Routes is an agent skill from adrianhajdin/react-native-lingua.

When should I use Expo API Routes?

Expo API Routes fits situations like: tasks that involve Cross-platform mobile apps.

How do I install Expo API Routes in Claude Code?

Run `npx skills add adrianhajdin/react-native-lingua --skill expo-api-routes -a claude-code`. Or copy the skill folder (.agents/skills/expo-api-routes in adrianhajdin/react-native-lingua) into .claude/skills/expo-api-routes in your project. Claude Code loads it when a task matches its description.

How do I install Expo API Routes in Codex?

Run `npx skills add adrianhajdin/react-native-lingua --skill expo-api-routes -a codex`. Or copy the skill folder (.agents/skills/expo-api-routes in adrianhajdin/react-native-lingua) into .agents/skills/expo-api-routes in your project. Codex loads it when a task matches its description.

Can I use Expo API Routes in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add adrianhajdin/react-native-lingua --skill expo-api-routes -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/expo-api-routes, .gemini/skills/expo-api-routes, .github/skills/expo-api-routes and .opencode/skills/expo-api-routes in your project.

What does Expo API Routes need to run?

Going by SKILL.md and its folder, Expo API Routes needs the command-line tools its instructions call (eas, curl, npx and npm) and credentials named OPENAI_API_KEY, TURSO_AUTH_TOKEN and WEATHER_API_KEY. Our summary lists: Node.js; A credential in OPENAI_API_KEY; A credential in TURSO_AUTH_TOKEN.

Does Expo API Routes access the network?

SKILL.md names 2 domains. In commands or code: api.openai.com and api.weather.com; the agent is likely to contact these when it follows the instructions. This is read from the text; nothing was executed.

Is Expo API Routes safe to install?

Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.

What licence does Expo API Routes use?

Expo API Routes is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Expo API Routes use?

About 2.2k tokens (SKILL.md is roughly 8.7k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Expo API Routes?

Skills that share tags, products or a category with Expo API Routes: Eas Hosting (expo/skills, 2.7k stars), React Native Best Practices (vercel-labs/openreview, 1.7k stars), Expo Cicd Workflows (CherryHQ/cherry-studio-app, 4k stars) and Expo Module (bbplayer-app/BBPlayer, 1.2k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Expo API Routes?

adrianhajdin (a GitHub user) maintains it in adrianhajdin/react-native-lingua, which has 152 GitHub stars. The repository holds 7 skills in this directory. The repository was last updated on May 15, 2026.

Source: adrianhajdin/react-native-lingua on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.