Communitygithub.com

expo/skills

Implante sites Expo e rotas de API do Expo Router no EAS Hosting – exporte o pacote web, execute eas deploy para produção e URLs de preview de PR, gerencie segredos de ambiente e domínios personalizados, e trabalhe no runtime do Cloudflare Workers. Também cobre a criação de rotas de API (handlers +api.ts, métodos HTTP, manipulação de requisições, CORS). Use ao implantar um app web Expo ou rotas de API, configurar EAS Hosting ou ambientes de hospedagem e domínios. Não é para builds nativos ou lançamentos em lojas – use a skill eas-app-stores para esses casos.

O que é skills?

Esta skill fornece orientação completa sobre como implantar sites Expo e rotas de API do Expo Router no EAS Hosting, um serviço pago da Expo com limites de nível gratuito. A documentação cobre desde a exportação do pacote web com `npx expo export -p web` até o deploy com `eas deploy`, incluindo a criação de previews para pull requests e deploys de produção. Além disso, explica detalhadamente como criar rotas de API usando o padrão +api.ts, manipular diferentes métodos HTTP (GET, POST, PUT, DELETE), trabalhar com parâmetros de consulta, cabeçalhos, corpo JSON, variáveis de ambiente e CORS. A skill também aborda o runtime do Cloudflare Workers, destacando suas limitações (sem sistema de arquivos Node.js, tempo de execução limitado) e fornecendo alternativas com APIs Web e opções de banco de dados compatíveis. É ideal para desenvolvedores que desejam implantar aplicações web Expo com backend serverless ou API routes, mas não cobre builds nativos para lojas de aplicativos.

Funciona com~Claude Code✓Codex CLI~Cursor
npx skills add https://github.com/expo/skills/tree/HEAD/plugins/expo/skills/eas-hosting

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

EAS Hosting

Serviço EAS – custos aplicam-se. EAS Hosting é um produto pago do Expo Application Services com limites de nível gratuito; deploys de produção usam a cota de requisições e largura de banda do seu plano. Veja https://expo.dev/pricing. Criar rotas de API e exportar o pacote web são gratuitos e de código aberto, e você pode hospedar a saída exportada do servidor por conta própria em vez de usar o EAS Hosting.

O EAS Hosting implanta seu app web Expo e rotas de API na borda gerenciada da Expo (Cloudflare Workers). Exporte o pacote web com npx expo export -p web e envie-o com eas deploy – o mesmo comando implanta quaisquer rotas de API do Expo Router empacotadas junto. Esta skill cobre a implantação de um site, a criação de rotas de API e o runtime de hospedagem; veja a seção de Implantação abaixo para o fluxo de deploy.

Quando Usar Rotas de API

Use rotas de API quando precisar de:

  • Segredos do lado do servidor — Chaves de API, credenciais de banco de dados ou tokens que nunca devem chegar ao cliente
  • Operações de banco de dados — Consultas diretas ao banco que não devem ser expostas
  • Proxies de APIs de terceiros — Ocultar chaves de API ao chamar serviços externos (OpenAI, Stripe, etc.)
  • Validação do lado do servidor — Validar dados antes de escrever no banco
  • Endpoints de webhook — Receber callbacks de serviços como Stripe ou GitHub
  • Limitação de taxa — Controlar o acesso no nível do servidor
  • Computação pesada — Descarregar processamento que seria lento no dispositivo móvel

Quando NÃO Usar Rotas de API

Evite rotas de API quando:

  • Os dados já são públicos — Use fetch direto para APIs públicas
  • Não há segredos necessários — Dados estáticos ou operações seguras para o cliente
  • Atualizações em tempo real são necessárias — Use WebSockets ou serviços como Supabase Realtime
  • CRUD simples — Considere Firebase, Supabase ou Convex para backends gerenciados
  • Upload de arquivos — Use uploads diretos para armazenamento (URLs pré-assinadas do S3, Cloudflare R2)
  • Apenas autenticação — Use Clerk, Auth0 ou Firebase Auth

Estrutura de Arquivos

As rotas de API ficam no diretório app com o sufixo +api.ts:

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

Rota de API Básica

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

Métodos HTTP

Exporte funções nomeadas para cada método HTTP:

// 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 });
}

Rotas Dinâmicas

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

Manipulação de Requisições

Parâmetros de Consulta

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 });
}

Cabeçalhos

export function GET(request: Request) {
  const auth = request.headers.get("Authorization");

  if (!auth) {
    return Response.json({ error: "Não autorizado" }, { status: 401 });
  }

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

Corpo JSON

export async function POST(request: Request) {
  const { email, password } = await request.json();

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

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

Variáveis de Ambiente

Use process.env para segredos do lado do servidor:

// 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);
}

Defina variáveis de ambiente:

  • Local: Crie o arquivo .env (nunca commitar)
  • EAS Hosting: Use eas env:create ou o painel da Expo

Cabeçalhos CORS

Adicione CORS para clientes web:

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: "valor" }, { headers: corsHeaders });
}

Tratamento de Erros

export async function POST(request: Request) {
  try {
    const body = await request.json();
    // Processar...
    return Response.json({ success: true });
  } catch (error) {
    console.error("Erro na API:", error);
    return Response.json({ error: "Erro interno do servidor" }, { status: 500 });
  }
}

Teste Local

Inicie o servidor de desenvolvimento com rotas de API:

npx expo serve

Isso inicia um servidor local em http://localhost:8081 com suporte completo a rotas de API.

Teste com curl:

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

Implantação no EAS Hosting

Pré-requisitos

npm install -g eas-cli
eas login

Implantar

Fazer o deploy envia seu pacote web e quaisquer rotas de API do Expo Router juntos – eas deploy lida com ambos. A exportação é executada independentemente de você ter um site completo, um backend apenas com rotas de API, ou ambos.

# Exportar o pacote web (inclui quaisquer rotas de API)
npx expo export -p web

# Implantar preview (URL estilo PR)
npx eas-cli@latest deploy

# Implantar em produção
npx eas-cli@latest deploy --prod

Tudo vai para o EAS Hosting (Cloudflare Workers).

Variáveis de Ambiente para Produção

# Criar um segredo
eas env:create --name OPENAI_API_KEY --value sk-xxx --environment production

# Ou use o painel da Expo

Domínio Personalizado

Configure em eas.json ou no painel da Expo.

Automatizar com EAS Workflows

Implante o site (e rotas de API) a cada push para a branch main com um workflow type: deploy:

.eas/workflows/deploy.yml

name: Implantar

on:
  push:
    branches:
      - main

# https://docs.expo.dev/eas/workflows/syntax/#deploy
jobs:
  deploy_web:
    type: deploy
    params:
      prod: true

Deploys de preview para pull requests usam o mesmo tipo de job com prod: false:

name: Preview Web de PR

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  preview:
    type: deploy
    params:
      prod: false

Para criar ou validar YAML de workflows além destes exemplos, use a skill eas-workflows.

Runtime do EAS Hosting (Cloudflare Workers)

As rotas de API são executadas no Cloudflare Workers. Principais limitações:

APIs Ausentes/Limitadas

  • Sem sistema de arquivos Node.js — módulo fs indisponível
  • Sem módulos Node nativos — Use APIs Web ou polyfills
  • Tempo de execução limitado — Timeout de 30 segundos para tarefas intensivas de CPU
  • Sem conexões persistentes — WebSockets exigem Durable Objects
  • fetch está disponível — Use fetch padrão para requisições HTTP

Use APIs Web

// Use Web Crypto em vez de Node crypto
const hash = await crypto.subtle.digest(
  "SHA-256",
  new TextEncoder().encode("dados")
);

// Use fetch em vez de node-fetch
const response = await fetch("https://api.example.com");

// Use Response/Request (já disponíveis)
return new Response(JSON.stringify(data), {
  headers: { "Content-Type": "application/json" },
});

Opções de Banco de Dados

Como o sistema de arquivos não está disponível, use bancos de dados em nuvem:

  • Cloudflare D1 — SQLite na borda
  • Turso — SQLite distribuído
  • PlanetScale — MySQL serverless
  • Supabase — Postgres com API REST
  • Neon — Postgres serverless

Exemplo com Turso:

// 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);
}

Chamando Rotas de API a partir do Cliente

// De componentes React Native
const response = await fetch("/api/hello");
const data = await response.json();

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

Padrões Comuns

Middleware de Autenticação

// 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: "Não autorizado" }), {
      status: 401,
      headers: { "Content-Type": "application/json" },
    });
  }

  // Verificar 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 de API Externa

// 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());
}

Regras

  • NUNCA exponha chaves de API ou segredos no código do cliente
  • SEMPRE valide e sanitize a entrada do usuário
  • Use códigos de status HTTP adequados (200, 201, 400, 401, 404, 500)
  • Trate erros graciosamente com try/catch
  • Mantenha as rotas de API focadas — uma responsabilidade por endpoint
  • Use TypeScript para segurança de tipos
  • Registre erros no lado do servidor para depuração

Enviando Feedback

Se você encontrar erros, informações enganosas ou desatualizadas nesta skill, reporte para que a Expo possa melhorar:

npx --yes @expo/agent-cli@latest feedback --category skills --subject "eas-hosting" "<feedback acionável>"

Envie apenas quando tiver algo específico e acionável para reportar. Inclua o máximo de contexto relevante possível. Se um agente falhar repetidamente em uma tarefa Expo ou o usuário tiver que intervir, envie um breve relatório da tarefa, resultado esperado e o que deu errado usando --category evals e o pacote Expo relevante ou comando como --subject.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

expo/add-app-clip

Add an iOS App Clip target to an Expo app. Use when the user mentions App Clip, AASA, apple-app-site-association, appclips, smart app banner, or wants to ship a lightweight iOS Clip invoked from a URL alongside their parent app.

expo/building-native-ui

Complete guide for building beautiful apps with Expo Router. Covers fundamentals, styling, components, navigation, animations, patterns, and native tabs.

expo/eas-update-insights

Check the health of published EAS Updates: crash rates, install/launch counts, unique users, payload size, and the split between embedded and OTA users per channel. Use when the user asks how an update is performing, whether a rollout is healthy, how many users are on the embedded build vs OTA, or wants to gate CI on update health.

expo/expo-api-routes

Guidelines for creating API routes in Expo Router with EAS Hosting

expo/expo-brownfield

Integrate Expo and React Native into an existing native iOS or Android app. Use when the user mentions brownfield, embedding React Native in a native app, AAR/XCFramework, or adding Expo to an existing Kotlin/Swift project. Covers both the isolated approach and the integrated approach.

expo/expo-cicd-workflows

Helps understand and write EAS workflow YAML files for Expo projects. Use this skill when the user asks about CI/CD or workflows in an Expo or EAS context, mentions .eas/workflows/, or wants help with EAS build pipelines or deployment automation.

expo/expo-deployment

Deploying Expo apps to iOS App Store, Android Play Store, web hosting, and API routes

expo/expo-dev-client

Build and distribute Expo development clients locally or via TestFlight

expo/expo-examples

Framework (OSS). Expo's official example projects - the expo/examples repo of ~70 `with-*` integrations (Stripe, Clerk, Supabase, OpenAI, maps, Reanimated, SQLite, Skia, NativeWind, and more). Use when integrating a third-party library or service into an existing Expo app and you want the canonical, version-matched pattern to adapt, or when scaffolding a new project from one with `npx create-expo --example`.

expo/expo-module

Guide for creating and writing Expo native modules and views using the Expo Modules API (Swift, Kotlin, TypeScript). Covers module definition DSL, native views, shared objects, config plugins, lifecycle hooks, autolinking, and type system. Use when building or modifying native modules for Expo.

expo/expo-observe

Use for anything related to EAS Observe — adding `expo-observe` to an Expo project (AppMetricsRoot/ObserveRoot HOC, markInteractive, the useObserve hook, and the Expo Router / React Navigation integrations for per-route metrics), querying via the EAS CLI (`eas observe:metrics-summary`, `observe:metrics`, `observe:routes`, `observe:events`, `observe:versions`), or interpreting the resulting metrics (cold/warm launch, TTR, TTI, navigation cold/warm TTR, update download, and the TTI frameRate params for triaging slow startups).

expo/expo-overview

Framework (OSS). Entry point and router for every Expo or EAS task. Load this skill first — before writing code and before choosing another expo-* / eas-* skill — when the request, PRD, or spec mentions Expo, EAS, Expo Go, or an expo-* package, or the project has an `expo` dependency in `package.json`. Within that gate it also covers app specs and designs to implement (tabs, stacks, maps, lists, navigation, building from a screenshot), and phrasings like 'implement a mobile app', 'make my app look native', 'add navigation', 'fetch some data', 'upgrade my SDK', 'add Expo to my existing native app', 'ship to the App Store', or 'I'm new to Expo, where do I start'. A fully specified request (SDK pinned, libraries named, layout given) still routes through here — the shared setup rules still apply. Do NOT load it when neither signal is present: a bare React Native project with no `expo` dependency is not Expo work. Detects the real goal, routes to the right expo-* / eas-* skill, and owns the shared setup rules.

expo/expo-router

Framework (OSS). Navigation and routing for Expo Router. Covers file-based routes, groups and dynamic routes, folder organization, Link with previews and context menus, native Stack, page titles, modals and form sheets, NativeTabs, headers and toolbars, and header search bars.

expo/expo-skill-eval

Evaluate Expo skills in this repo end-to-end - trigger accuracy, generated code quality, and runtime screenshots on iOS simulator and Android emulator via Expo Go (web optional). Use when the user wants to eval an Expo skill, test that a skill produces working code, benchmark a skill with device screenshots, or verify a skill's output renders correctly.

expo/expo-tailwind-setup

Set up Tailwind CSS v4 in Expo with react-native-css and NativeWind v5 for universal styling

expo/expo-ui

Framework (OSS). Build native UI with the @expo/ui package: real SwiftUI on iOS and Jetpack Compose on Android. Default to @expo/ui for sheets (BottomSheet), pickers, sliders, toggles, menus, and grouped-form sections — do NOT reach for Reanimated, @gorhom/bottom-sheet, or RN built-in Picker/Switch; use @expo/ui instead. Fall back to RN built-ins only when @expo/ui is missing the component. NOTE: @expo/ui List renders native grouped rows like an iOS Settings screen — it is NOT a virtualized list; use FlatList/FlashList for large datasets. Covers universal components (Host, Column, Row, Button, Text, List, BottomSheet, FieldGroup, Switch, Slider, Picker, Menu), drop-in replacements for RN community libraries, and platform-specific SwiftUI/Jetpack Compose trees. Not for Expo Router navigation, Reanimated, or data fetching.

expo/expo-ui-jetpack-compose

`@expo/ui/jetpack-compose` package lets you use Jetpack Compose Views and modifiers in your app.

expo/expo-ui-swiftui

`@expo/ui/swift-ui` package lets you use SwiftUI Views and modifiers in your app.

expo/expo-upgrade

Framework (OSS). Guidelines for upgrading Expo SDK versions and fixing dependency issues

expo/native-data-fetching

Use when implementing or debugging ANY network request, API call, or data fetching. Covers fetch API, React Query, SWR, error handling, caching, offline support, and Expo Router data loaders (`useLoaderData`).

Habilidades Relacionadas