Skip to content

feat: add TanStack Start adapter#74

Open
wobsoriano wants to merge 3 commits into
supabase:mainfrom
wobsoriano:rob/tanstack-start-adapter
Open

feat: add TanStack Start adapter#74
wobsoriano wants to merge 3 commits into
supabase:mainfrom
wobsoriano:rob/tanstack-start-adapter

Conversation

@wobsoriano

@wobsoriano wobsoriano commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

What kind of change does this PR introduce?

Feature

What is the current behavior?

Developers building apps with TanStack Start have to wire up Supabase auth manually with the core primitives in every server function and server route.

What is the new behavior?

Adds @supabase/server/adapters/tanstack-start, a first-class request middleware adapter for TanStack Start. It exposes withSupabase as a TanStack Start request middleware, so the same middleware works for both server functions and server routes; in either, the SupabaseContext is available (and typed) as context.supabaseContext in the handler.

It is framework-agnostic: it imports from @tanstack/start-client-core, which every @tanstack/{react,solid,vue}-start package re-exports. So one adapter covers React, Solid, and Vue Start.

Usage in a server function:

import { createServerFn } from '@tanstack/react-start'
import { withSupabase } from '@supabase/server/adapters/tanstack-start'

export const getTodos = createServerFn()
  .middleware([withSupabase({ auth: 'user' })])
  .handler(async ({ context }) => {
    const { data } = await context.supabaseContext.supabase
      .from('todos')
      .select()
    return data
  })

Usage in a server route (src/routes/api/todos.ts):

import { createFileRoute } from '@tanstack/react-router'
import { withSupabase } from '@supabase/server/adapters/tanstack-start'

export const Route = createFileRoute('/api/todos')({
  server: {
    middleware: [withSupabase({ auth: 'user' })],
    handlers: {
      GET: async ({ context }) => {
        const { data } = await context.supabaseContext.supabase
          .from('todos')
          .select()
        return Response.json(data)
      },
    },
  },
})

Per-route auth, since middleware is attached per server function or per route:

// User-authenticated
export const listTodos = createServerFn()
  .middleware([withSupabase({ auth: 'user' })])
  .handler(async ({ context }) => context.supabaseContext.userClaims)

// Secret-key-protected (e.g. a trusted server-to-server call)
export const syncAuditLog = createServerFn({ method: 'POST' })
  .middleware([withSupabase({ auth: 'secret' })])
  .handler(async ({ context }) =>
    context.supabaseContext.supabaseAdmin
      .from('audit_log')
      .insert({ action: 'sync' }),
  )

Additional context

  • Test coverage mirrors the Hono and H3 adapter tests.
  • Docs and package metadata were updated to include TanStack Start in the adapter tables, exports, jsr.json, and build entry.

@wobsoriano wobsoriano marked this pull request as ready for review June 12, 2026 21:38
@wobsoriano wobsoriano requested review from a team as code owners June 12, 2026 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant