tanstack-start-api-routes

$npx mdskill add netlify/swar-templates/tanstack-start-api-routes

Use createFileRoute with server.handlers for raw HTTP endpoints. Use createServerFn when a page needs typed RPC instead. These are TanStack Start routes, not Next.js route handlers or a separate Express server.

SKILL.md

.github/skills/tanstack-start-api-routesView on GitHub ↗
---
name: tanstack-start-api-routes
description: Create API routes (server routes) in TanStack Start for handling HTTP requests. Use when building REST APIs, webhooks, or any HTTP endpoint that returns data rather than rendering a page.
license: Apache-2.0
metadata:
  author: tanstack
  version: "1.0"
---

# HTTP server routes

Use createFileRoute with server.handlers for raw HTTP endpoints. Use createServerFn when a page needs typed RPC instead. These are TanStack Start routes, not Next.js route handlers or a separate Express server.

## Complete JSON endpoints

```ts file=src/routes/api.hello.ts
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/api/hello')({
  server: { handlers: {
    GET: () => Response.json({ message: 'Hello' }),
  } },
})
```

```ts file=src/routes/api.echo.ts
import { createFileRoute } from '@tanstack/react-router'
import { z } from 'zod'

const input = z.object({ message: z.string().trim().min(1).max(500) })

export const Route = createFileRoute('/api/echo')({
  server: { handlers: {
    POST: async ({ request }) => {
      let body: unknown
      try { body = await request.json() } catch {
        return Response.json({ error: 'Invalid JSON' }, { status: 400 })
      }
      const parsed = input.safeParse(body)
      if (!parsed.success) return Response.json({ error: 'A message is required' }, { status: 400 })
      return Response.json({ message: parsed.data.message })
    },
  } },
})
```

The echo endpoint validates and returns input only; it does not save a record. Zod must be declared in the generated app before using the example. request, params, and route middleware context come from the handler argument. Read query parameters from new URL(request.url).searchParams.

## Response and integration rules

Use Response.json for JSON, new Response for text/bytes, Response.redirect with an absolute trusted destination, and new Response(null, { status: 204 }) for no content. Use status, not a v1 Lambda statusCode object. Return an explicit Response from a handler; do not assume returning undefined renders a page. For combined page/API handling, follow the installed handler's next() contract.

Validate JSON, query values, route parameters, and form fields at runtime. Use request.text() for signed webhook bodies before verifying the signature; JSON parsing first changes the signed bytes. Check required secrets/signatures before calling a provider library. Do not add fulfillment or webhook processing to a checkout-only example unless requested.

Enforce authorization inside every protected endpoint. A page guard is not an API permission check. Use the Netlify Identity integration rather than an undefined verifyToken helper or hand-written JWT parser. Do not add wildcard CORS to a same-origin app; cross-origin access needs an explicit trusted origin policy.

For external API requests, check response.ok and validate response data before using it. Do not return internal stack traces, upstream response bodies, keys, or tokens in error messages. File uploads need field, size, and type checks, plus the appropriate storage integration if persistence is requested.

| File | Endpoint |
| --- | --- |
| api.hello.ts | /api/hello |
| api/items.ts | /api/items |
| api.items.$itemId.ts | /api/items/:itemId |
| api.files.$.ts | /api/files/* |

Generate route types after adding server routes and check both status and body locally. A build proves compilation, not that a request was accepted or a side effect happened.

More from netlify/swar-templates

SkillDescription
content-collectionsUse content-collections for type-safe content management with markdown files. Use when building blogs, documentation sites, or any content-driven pages with frontmatter and markdown.
netlify-forms-tanstackHandle Netlify Forms in TanStack Start. Use when implementing contact forms, signup forms, or any form submission handling on Netlify-hosted TanStack Start sites.
netlify-identity-tanstack-startUpgrade a stock TanStack Start project to use Netlify Identity for authentication via the @netlify/identity package. Use this skill whenever the user wants to add Netlify Identity auth to a TanStack Start app, integrate login/signup into TanStack Start, protect routes or server functions with Netlify Identity, add role-based access control, or wire up Netlify Identity webhooks. Also use when the user mentions '@netlify/identity', 'nf_jwt', or asks about auth for TanStack Start on Netlify. Covers SSR pages, SPA pages, API routes, server functions, middleware, route guards, role-based access, identity webhooks, and client-side auth state.
tanstack-start-loadersLoad data for TanStack Start routes using beforeLoad and loader functions. Use when fetching data for pages, implementing route guards, or setting up route context. IMPORTANT - Loaders should call server functions for data access.
tanstack-start-project-setupSet up and configure TanStack Start projects. Use when creating new projects, configuring the router, setting up TanStack Query integration, or configuring build settings.
tanstack-start-routesCreate and manage routes in TanStack Start using file-based routing. Use when adding new pages, configuring layouts, setting up nested routes, or working with route parameters.
tanstack-start-server-functionsCreate validated TanStack Start server functions and composable middleware for server-only logic called from loaders or components.
tanstack-start-typesafe-routingImplement type-safe navigation and links in TanStack Start. Use when creating links, navigating programmatically, working with search params, or accessing route parameters with full TypeScript support.