---
id: server-routes
track: learn
product: start
locale: en
order: 8
revision: 2
sourceCheckedOn: "2026-08-03"
versionRange: "Start ^1 / Router ^1"
verifiedAgainst: "@tanstack/react-start@1.168.34 + @tanstack/react-router@1.170.18"
contentModel: 2
prerequisites:
  - "Understand the in-app RPC boundary of Server Functions"
  - "Basic HTTP status codes"
sourceRefs:
  - "https://tanstack.com/start/latest/docs/framework/react/guide/server-routes"
  - "https://tanstack.com/start/latest/docs/framework/react/guide/server-functions"
---

# Put external endpoints in a Server Route

> Separate application RPC from public HTTP endpoints and use a native Response to express status, body, and cache policy.

**Outcome:** Choose a Server Route when appropriate and return correct HTTP responses for success and failure.

## Start with who will call it

Prefer a Server Function when only the current Start app calls the operation and end-to-end types matter. Use a Server Route for webhooks, third-party clients, mobile apps, or a stable HTTP contract. Both run on the server, but they serve different callers.

## Return complete HTTP semantics

A Server Route handler returns a Response directly. Set status 404 explicitly when a resource is absent instead of throwing the page-router notFound() helper. Choose no-store, private, or shared caching for successful data according to whether identity affects it.

File: `src/routes/api/issues/$issueId.ts`

```ts
import { createFileRoute } from '@tanstack/react-router'
import { findIssue } from '~/server/issues'

export const Route = createFileRoute('/api/issues/$issueId')({
  server: {
    handlers: {
      GET: async ({ params }) => {
        const issue = await findIssue(params.issueId)
        if (!issue) {
          return Response.json({ error: 'Issue not found' }, { status: 404 })
        }

        return Response.json(issue, {
          headers: { 'Cache-Control': 'no-store' },
        })
      },
    },
  },
})
```

## Treat it as a real external boundary

Path params, search params, headers, and bodies all come from untrusted callers. Validate at runtime and enforce authentication, authorization, and rate limits before writes. Keep error bodies stable and never expose stacks, SQL, or internal file paths.

## Practice and verification

### Completion checkpoint

An external client can call the endpoint with standard HTTP and receive explicit status, headers, and body.

### Exercise

Add a GET `/api/issues/$issueId` endpoint with distinct success, invalid-parameter, and missing-resource responses.

### Verification

Use curl to verify all three responses, including Content-Type, status code, and JSON shape.

### Common pitfalls

- Implementing a public external API as a server-function RPC.
- Always returning 200 and hiding errors inside JSON fields.

## Official sources

- https://tanstack.com/start/latest/docs/framework/react/guide/server-routes
- https://tanstack.com/start/latest/docs/framework/react/guide/server-functions
